diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dda5698 --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +*.o +*.moc +*.pyc +.~lock* +*~ +.directory +*.kate-swp +ui/*.h +bin/* +!bin/.dir +perf.data +perf.data.old +gmon.out +Debug/* +Release/* +build/* +.clang/* +.codelite/* +.settings/* +takin.txt +takin.mk +montereso.txt +montereso.mk +monteconvo.txt +monteconvo.mk +scanviewer.txt +scanviewer.mk +CMakeFiles/* +CMakeCache.txt +cmake_install.cmake +FindQwt.cmake +Makefile +tlibs-master.tar.bz2 +tlibs/* +tlibs +tango-icon-theme*.tar.gz +tmp/* +res/* +!res/brillouin.svg +!res/ellipses.svg +!res/goto.svg +!res/q.svg +*.htm +*.html +!doc/index_help.html +!doc/toc.html +!doc/takin.html +!doc/basics.html +!doc/reso.html +!doc/convo.html +!doc/fit.html +!doc/reso-sqw.html +!doc/reso-sqw-native.html +!doc/reso-sqw-py.html +takin.log +*.qch +*.qhc diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..1a0be58 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Tobias Weber diff --git a/CMakeLists-dynamic.txt b/CMakeLists-dynamic.txt new file mode 100644 index 0000000..f36661d --- /dev/null +++ b/CMakeLists-dynamic.txt @@ -0,0 +1,224 @@ +# +# Takin +# @author tweber +# @date 2013-2016 +# @license GPLv2 +# + +project(takin) +cmake_minimum_required(VERSION 3.0) + +#set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_BUILD_TYPE Release) + + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}" ".") +set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}") +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") + +find_package(Boost REQUIRED COMPONENTS iostreams system filesystem regex python REQUIRED) +find_package(Threads REQUIRED) +find_package(tlibs REQUIRED) +find_package(Qt4 REQUIRED) +find_package(PythonInterp 2.7 REQUIRED) +find_package(PythonLibs 2.7 REQUIRED) +find_package(PNG REQUIRED) +#find_package(JPEG REQUIRED) +#find_package(TIFF REQUIRED) +find_package(Qwt REQUIRED) +find_package(Clipper REQUIRED) + +list(APPEND CMAKE_MODULE_PATH "${tlibs_SHARED_DIRS}") +find_package(Minuit2 REQUIRED) + + +#message("Project source dir: ${PROJECT_SOURCE_DIR}") +#message("CMake source dir: ${CMAKE_SOURCE_DIR}") +#message("Binary dir: ${CMAKE_BINARY_DIR}") +message("Install path prefix: ${CMAKE_INSTALL_PREFIX}") +message("Using qwt version ${QWT_MAJOR_VERSION}") +message("Qt moc: ${QT_MOC_EXECUTABLE}\nQt uic: ${QT_UIC_EXECUTABLE}") + +add_definitions(-DNDEBUG) +add_definitions(-DUSE_NET -DUSE_IOSTR -DUSE_BOOST_REX -DUSE_PY -DUSE_GIL) +add_definitions(-DQT_VER=4 -DQWT_VER=${QWT_MAJOR_VERSION}) +add_definitions(-DNO_LAPACK -DNO_3D -DNO_CLP) +add_definitions(-DNO_JPEG -DNO_TIFF) +add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +add_definitions(${Boost_CXX_FLAGS}) + + +include_directories("${PROJECT_SOURCE_DIR}" ".") +include_directories("${Boost_INCLUDE_DIRS}/..") +include_directories("${tlibs_INCLUDE_DIRS}/..") +include_directories("${PYTHON_INCLUDE_DIRS}") +include_directories("${PNG_INCLUDE_DIRS}") +#include_directories("${JPEG_INCLUDE_DIRS} ${TIFF_INCLUDE_DIRS}") +include_directories("${QWT_INCLUDE_DIRS}") +include_directories("${Minuit2_INCLUDE_DIRS}") + + +set(CMAKE_AUTOMOC OFF) +set(CMAKE_AUTOUIC OFF) + +add_definitions(-std=c++11) +#add_definitions(-march=native -s) + + + +# ----------------------------------------------------------------------------- +# gentab +# ----------------------------------------------------------------------------- +add_executable(gentab + tools/gentab/gentab.cpp + libs/spacegroups/spacegroup_clp.cpp libs/spacegroups/crystalsys.cpp +) + +target_link_libraries(gentab + ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${Clipper_LIBRARIES} ${tlibs_LIBRARIES} + Qt4::QtCore Qt4::QtGui +) + +add_custom_command(TARGET gentab POST_BUILD + COMMAND cd ${CMAKE_BINARY_DIR} && ./gentab + MAIN_DEPENDENCY gentab) +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# takin +# ----------------------------------------------------------------------------- +add_executable(takin + tools/taz/taz_main.cpp + tools/taz/taz.cpp tools/taz/tas_layout.cpp tools/taz/tof_layout.cpp + tools/taz/taz_crys.cpp + tools/taz/taz_file.cpp tools/taz/taz_export.cpp + tools/taz/tas_layout.cpp tools/taz/scattering_triangle.cpp + tools/taz/real_lattice.cpp tools/taz/proj_lattice.cpp + tools/taz/nicos.cpp tools/taz/sics.cpp tools/taz/taz_net.cpp + + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp tools/res/simple.cpp + tools/res/ResoDlg.cpp + + tools/monteconvo/ConvoDlg.cpp tools/monteconvo/SqwParamDlg.cpp tools/monteconvo/TASReso.cpp + tools/monteconvo/sqw.cpp tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwfactory.cpp + tools/monteconvo/sqw_py.cpp + + tools/convofit/scan.cpp + tools/scanviewer/scanviewer.cpp + + dialogs/SettingsDlg.cpp dialogs/FilePreviewDlg.cpp + dialogs/GotoDlg.cpp dialogs/DWDlg.cpp dialogs/DynPlaneDlg.cpp + dialogs/NeutronDlg.cpp dialogs/SpurionDlg.cpp dialogs/PowderDlg.cpp + dialogs/DispDlg.cpp + dialogs/RecipParamDlg.cpp dialogs/RealParamDlg.cpp + dialogs/SrvDlg.cpp dialogs/NetCacheDlg.cpp + dialogs/EllipseDlg.cpp dialogs/FormfactorDlg.cpp + dialogs/AtomsDlg.cpp dialogs/AboutDlg.cpp + + libs/spacegroups/spacegroup.cpp tools/sglist/SgListDlg.cpp + libs/globals.cpp libs/globals_qt.cpp libs/spacegroups/crystalsys.cpp + libs/formfactors/formfact.cpp libs/qthelper.cpp +# libs/plotgl.cpp tools/taz/recip3d.cpp dialogs/EllipseDlg3D.cpp +) + +target_link_libraries(takin + ${Boost_LIBRARIES} ${tlibs_LIBRARIES} + Threads::Threads + Qt4::QtCore Qt4::QtGui Qt4::QtSvg #Qt4::QtOpenGL + ${PYTHON_LIBRARIES} + ${PNG_LIBRARIES} +# ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} + ${QWT_LIBRARIES} +) + + +# pre-build +add_custom_target(prebuild-script + COMMAND ${PROJECT_SOURCE_DIR}/prebuild.sh ${QT_UIC_EXECUTABLE} ${QT_MOC_EXECUTABLE} ${PROJECT_SOURCE_DIR} +) + + +# post-build +#add_custom_command(TARGET takin POST_BUILD +# COMMAND qcollectiongenerator ${PROJECT_SOURCE_DIR}/doc/takin.qhcp -o ${PROJECT_SOURCE_DIR}/doc/takin.qhc +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qhc ${PROJECT_SOURCE_DIR}/res/ +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qch ${PROJECT_SOURCE_DIR}/res/ +# MAIN_DEPENDENCY takin) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET takin POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY takin + ) +endif() + + +add_dependencies(takin prebuild-script) +add_dependencies(takin gentab) +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# convofit, convoseries +# ----------------------------------------------------------------------------- +add_executable(convofit + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp + #tools/res/simple.cpp + + tools/monteconvo/TASReso.cpp + tools/monteconvo/sqw.cpp tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwfactory.cpp + tools/monteconvo/sqw_py.cpp + + tools/convofit/convofit.cpp + tools/convofit/model.cpp tools/convofit/scan.cpp +) + +set_target_properties(convofit PROPERTIES COMPILE_FLAGS "-DNO_QT") + +target_link_libraries(convofit + ${tlibs_LIBRARIES} Threads::Threads + ${Boost_LIBRARIES} ${Minuit2_LIBRARIES} ${PYTHON_LIBRARIES} +) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET convofit POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY convofit + ) +endif() +# ----------------------------------------------------------------------------- + +add_executable(convoseries + tools/convofit/scanseries.cpp +) + +set_target_properties(convoseries PROPERTIES COMPILE_FLAGS "-DNO_QT") + +target_link_libraries(convoseries + ${tlibs_LIBRARIES} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} +) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET convoseries POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY convoseries + ) +endif() +# ----------------------------------------------------------------------------- + + + + +# ----------------------------------------------------------------------------- +# install +# ----------------------------------------------------------------------------- +install(TARGETS takin DESTINATION bin) +install(TARGETS convofit convoseries DESTINATION bin) +install(DIRECTORY ${PROJECT_SOURCE_DIR}/res ${PROJECT_SOURCE_DIR}/examples ${PROJECT_SOURCE_DIR}/doc + DESTINATION share/takin) +install(FILES ${PROJECT_SOURCE_DIR}/COPYING ${PROJECT_SOURCE_DIR}/AUTHORS ${PROJECT_SOURCE_DIR}/LICENSES + DESTINATION share/takin) +# ----------------------------------------------------------------------------- diff --git a/CMakeLists-static-cli.txt b/CMakeLists-static-cli.txt new file mode 100644 index 0000000..507e703 --- /dev/null +++ b/CMakeLists-static-cli.txt @@ -0,0 +1,77 @@ +# +# Takin, cli client +# @author tweber +# @date 2014-2016 +# @license GPLv2 +# + +project(takincli) +cmake_minimum_required(VERSION 3.0) + +#set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_BUILD_TYPE Release) + + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}" "." "${PROJECT_SOURCE_DIR}/tlibs") +set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}") +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") + +find_package(Boost REQUIRED COMPONENTS iostreams system filesystem regex REQUIRED) +find_package(Threads REQUIRED) + +#message("Project source dir: ${PROJECT_SOURCE_DIR}") +#message("CMake source dir: ${CMAKE_SOURCE_DIR}") +#message("Binary dir: ${CMAKE_BINARY_DIR}") +message("Install path prefix: ${CMAKE_INSTALL_PREFIX}") + +add_definitions(-DNDEBUG) +add_definitions(-DUSE_NET -DUSE_IOSTR -DUSE_BOOST_REX) +add_definitions(-DNO_LAPACK -DNO_3D -DNO_CLP -DNO_QT) +add_definitions(-DNO_JPEG -DNO_TIFF -DNO_PNG) +add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +add_definitions(${Boost_CXX_FLAGS}) +add_definitions(-DTLIBS_INC_HDR_IMPLS) + + +include_directories("${PROJECT_SOURCE_DIR}" ".") +include_directories("${Boost_INCLUDE_DIRS}/..") + +add_definitions(-std=c++11) +#add_definitions(-march=native -s) + + +# ----------------------------------------------------------------------------- +add_executable(takincli + tools/cli/cli_main.cpp + + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp + tools/res/simple.cpp + tools/monteconvo/TASReso.cpp + + # statically link to tlibs externals + tlibs/log/log.cpp + tlibs/math/rand.cpp + #tlibs/file/loadinstr.cpp + #tlibs/fit/minuit.cpp + #libs/globals.cpp +) + +target_link_libraries(takincli + Threads::Threads ${Boost_LIBRARIES} +) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET takincli POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY takincli + ) +endif() +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# install +# ----------------------------------------------------------------------------- +install(TARGETS takincli DESTINATION bin) +# ----------------------------------------------------------------------------- diff --git a/CMakeLists-static-mingw.txt b/CMakeLists-static-mingw.txt new file mode 100644 index 0000000..f640a7b --- /dev/null +++ b/CMakeLists-static-mingw.txt @@ -0,0 +1,144 @@ +# +# Takin +# @author tweber +# @date 2013-2016 +# @license GPLv2 +# + +project(takin) +cmake_minimum_required(VERSION 3.0) + +#set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_BUILD_TYPE Release) + + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}" "." "${PROJECT_SOURCE_DIR}/tlibs") +set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}") +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") + +find_package(Boost REQUIRED COMPONENTS iostreams system filesystem regex REQUIRED) +find_package(Threads REQUIRED) +find_package(Qt4 REQUIRED) +find_package(PNG REQUIRED) +find_package(Qwt REQUIRED) + +message("Install path prefix: ${CMAKE_INSTALL_PREFIX}") +message("Using qwt version ${QWT_MAJOR_VERSION}") +message("Qt moc: ${QT_MOC_EXECUTABLE}\nQt uic: ${QT_UIC_EXECUTABLE}") + +add_definitions(-DNDEBUG -DIS_EXPERIMENTAL_BUILD) +add_definitions(-DUSE_NET -DUSE_IOSTR -DUSE_BOOST_REX -DUSE_PY -DUSE_GIL) +add_definitions(-DQT_VER=4 -DQWT_VER=${QWT_MAJOR_VERSION}) +add_definitions(-DNO_LAPACK -DNO_3D -DNO_CLP) +add_definitions(-DNO_JPEG -DNO_TIFF) +add_definitions(-DNO_PY) +add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +add_definitions(${Boost_CXX_FLAGS}) +add_definitions(-DTLIBS_INC_HDR_IMPLS) + + +include_directories("${PROJECT_SOURCE_DIR}" ".") +include_directories("${Boost_INCLUDE_DIRS}/..") +include_directories("${PNG_INCLUDE_DIRS}") +include_directories("${QWT_INCLUDE_DIRS}") + + +set(CMAKE_AUTOMOC OFF) +set(CMAKE_AUTOUIC OFF) + +add_definitions(-std=c++11) +add_definitions(-O3 -s) +add_definitions(-mtune=native -ffast-math) +#add_definitions(-march=native) + + + +# ----------------------------------------------------------------------------- +# takin +# ----------------------------------------------------------------------------- +add_executable(takin + tools/taz/taz_main.cpp + tools/taz/taz.cpp tools/taz/tas_layout.cpp tools/taz/tof_layout.cpp + tools/taz/taz_crys.cpp + tools/taz/taz_file.cpp tools/taz/taz_export.cpp + tools/taz/tas_layout.cpp tools/taz/scattering_triangle.cpp + tools/taz/real_lattice.cpp tools/taz/proj_lattice.cpp + tools/taz/nicos.cpp tools/taz/sics.cpp tools/taz/taz_net.cpp + + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp tools/res/simple.cpp + tools/res/ResoDlg.cpp + + tools/monteconvo/ConvoDlg.cpp tools/monteconvo/SqwParamDlg.cpp tools/monteconvo/TASReso.cpp + tools/monteconvo/sqw.cpp tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwfactory.cpp + + tools/convofit/scan.cpp + tools/scanviewer/scanviewer.cpp + + dialogs/SettingsDlg.cpp dialogs/FilePreviewDlg.cpp + dialogs/GotoDlg.cpp dialogs/DWDlg.cpp dialogs/DynPlaneDlg.cpp + dialogs/NeutronDlg.cpp dialogs/SpurionDlg.cpp dialogs/PowderDlg.cpp + dialogs/DispDlg.cpp + dialogs/RecipParamDlg.cpp dialogs/RealParamDlg.cpp + dialogs/SrvDlg.cpp dialogs/NetCacheDlg.cpp + dialogs/EllipseDlg.cpp dialogs/FormfactorDlg.cpp + dialogs/AtomsDlg.cpp dialogs/AboutDlg.cpp + + libs/spacegroups/spacegroup.cpp tools/sglist/SgListDlg.cpp + libs/globals.cpp libs/globals_qt.cpp libs/spacegroups/crystalsys.cpp + libs/formfactors/formfact.cpp libs/qthelper.cpp +# libs/plotgl.cpp tools/taz/recip3d.cpp dialogs/EllipseDlg3D.cpp + + + # statically link tlibs externals + #tlibs/file/loadinstr.cpp + tlibs/file/recent.cpp tlibs/file/x3d.cpp + tlibs/log/log.cpp tlibs/log/debug.cpp + tlibs/math/rand.cpp + tlibs/string/spec_char.cpp + tlibs/helper/flags.cpp tlibs/version.cpp +) + +target_link_libraries(takin + ${Boost_LIBRARIES} ws2_32 Threads::Threads + Qt4::QtCore Qt4::QtGui Qt4::QtSvg #Qt4::QtOpenGL + ${PYTHON_LIBRARIES} + ${PNG_LIBRARIES} + ${QWT_LIBRARIES} +) + + +# pre-build +add_custom_target(prebuild-script + COMMAND ${PROJECT_SOURCE_DIR}/prebuild.sh ${QT_UIC_EXECUTABLE} ${QT_MOC_EXECUTABLE} ${PROJECT_SOURCE_DIR} +) + + +# post-build +#add_custom_command(TARGET takin POST_BUILD +# COMMAND qcollectiongenerator ${PROJECT_SOURCE_DIR}/doc/takin.qhcp -o ${PROJECT_SOURCE_DIR}/doc/takin.qhc +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qhc ${PROJECT_SOURCE_DIR}/res/ +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qch ${PROJECT_SOURCE_DIR}/res/ +# MAIN_DEPENDENCY takin) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET takin POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY takin + ) +endif() + + +add_dependencies(takin prebuild-script) +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# install +# ----------------------------------------------------------------------------- +install(TARGETS takin DESTINATION takin) +install(DIRECTORY ${PROJECT_SOURCE_DIR}/res ${PROJECT_SOURCE_DIR}/examples ${PROJECT_SOURCE_DIR}/doc + DESTINATION share/takin) +install(FILES ${PROJECT_SOURCE_DIR}/COPYING ${PROJECT_SOURCE_DIR}/AUTHORS ${PROJECT_SOURCE_DIR}/LICENSES + DESTINATION takin) +# ----------------------------------------------------------------------------- diff --git a/CMakeLists-static.txt b/CMakeLists-static.txt new file mode 100644 index 0000000..43dd508 --- /dev/null +++ b/CMakeLists-static.txt @@ -0,0 +1,243 @@ +# +# Takin +# @author tweber +# @date 2013-2016 +# @license GPLv2 +# + + +project(takin) +cmake_minimum_required(VERSION 3.0) + +#set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_BUILD_TYPE Release) + + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}" "." "${PROJECT_SOURCE_DIR}/tlibs") +set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}") +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") + +find_package(Boost REQUIRED COMPONENTS iostreams system filesystem regex python REQUIRED) +find_package(Threads REQUIRED) +find_package(Qt4 REQUIRED) +find_package(PNG REQUIRED) +find_package(Qwt REQUIRED) +#find_package(Freetype REQUIRED) +find_package(PythonInterp 2.7 REQUIRED) +find_package(PythonLibs 2.7 REQUIRED) +find_package(Minuit2 REQUIRED) +find_package(Clipper REQUIRED) + +#message("Project source dir: ${PROJECT_SOURCE_DIR}") +#message("CMake source dir: ${CMAKE_SOURCE_DIR}") +#message("Binary dir: ${CMAKE_BINARY_DIR}") +message("Install path prefix: ${CMAKE_INSTALL_PREFIX}") +message("Using qwt version ${QWT_MAJOR_VERSION}") +message("Qt moc: ${QT_MOC_EXECUTABLE}\nQt uic: ${QT_UIC_EXECUTABLE}") + +add_definitions(-DNDEBUG) +add_definitions(-DUSE_NET -DUSE_IOSTR -DUSE_BOOST_REX -DUSE_PY -DUSE_GIL) +add_definitions(-DQT_VER=4 -DQWT_VER=${QWT_MAJOR_VERSION}) +add_definitions(-DNO_LAPACK -DNO_3D -DNO_CLP) +add_definitions(-DNO_JPEG -DNO_TIFF) +add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +add_definitions(${Boost_CXX_FLAGS}) +add_definitions(-DTLIBS_INC_HDR_IMPLS) + + +include_directories("${PROJECT_SOURCE_DIR}" ".") +include_directories("${Boost_INCLUDE_DIRS}/..") +include_directories("${PYTHON_INCLUDE_DIRS}") +include_directories("${PNG_INCLUDE_DIRS}") +#include_directories("${JPEG_INCLUDE_DIRS} ${TIFF_INCLUDE_DIRS}") +include_directories("${QT_INCLUDE_DIR}") +include_directories("${QWT_INCLUDE_DIRS}") +#include_directories("${FREETYPE_INCLUDE_DIRS}") +include_directories("${Minuit2_INCLUDE_DIRS}") + + +set(CMAKE_AUTOMOC OFF) +set(CMAKE_AUTOUIC OFF) + +add_definitions(-std=c++11) +#add_definitions(-march=native -s) + + + +# ----------------------------------------------------------------------------- +# gentab +# ----------------------------------------------------------------------------- +add_executable(gentab + tools/gentab/gentab.cpp + libs/spacegroups/spacegroup_clp.cpp libs/spacegroups/crystalsys.cpp + tlibs/log/log.cpp +) + +target_link_libraries(gentab + ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${Clipper_LIBRARIES} + Qt4::QtCore Qt4::QtGui +) + +add_custom_command(TARGET gentab POST_BUILD + COMMAND cd ${CMAKE_BINARY_DIR} && ./gentab + MAIN_DEPENDENCY gentab) +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# takin +# ----------------------------------------------------------------------------- +add_executable(takin + tools/taz/taz_main.cpp + tools/taz/taz.cpp tools/taz/tas_layout.cpp tools/taz/tof_layout.cpp + tools/taz/taz_crys.cpp + tools/taz/taz_file.cpp tools/taz/taz_export.cpp + tools/taz/tas_layout.cpp tools/taz/scattering_triangle.cpp + tools/taz/real_lattice.cpp tools/taz/proj_lattice.cpp + tools/taz/nicos.cpp tools/taz/sics.cpp tools/taz/taz_net.cpp + + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp tools/res/simple.cpp + tools/res/ResoDlg.cpp + + tools/monteconvo/ConvoDlg.cpp tools/monteconvo/SqwParamDlg.cpp tools/monteconvo/TASReso.cpp + tools/monteconvo/sqw.cpp tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwfactory.cpp + tools/monteconvo/sqw_py.cpp + + tools/convofit/scan.cpp + tools/scanviewer/scanviewer.cpp + + dialogs/SettingsDlg.cpp dialogs/FilePreviewDlg.cpp + dialogs/GotoDlg.cpp dialogs/DWDlg.cpp dialogs/DynPlaneDlg.cpp + dialogs/NeutronDlg.cpp dialogs/SpurionDlg.cpp dialogs/PowderDlg.cpp + dialogs/DispDlg.cpp + dialogs/RecipParamDlg.cpp dialogs/RealParamDlg.cpp + dialogs/SrvDlg.cpp dialogs/NetCacheDlg.cpp + dialogs/EllipseDlg.cpp dialogs/FormfactorDlg.cpp + dialogs/AtomsDlg.cpp dialogs/AboutDlg.cpp + + libs/spacegroups/spacegroup.cpp tools/sglist/SgListDlg.cpp + libs/globals.cpp libs/globals_qt.cpp libs/spacegroups/crystalsys.cpp + libs/formfactors/formfact.cpp libs/qthelper.cpp +# libs/plotgl.cpp tools/taz/recip3d.cpp dialogs/EllipseDlg3D.cpp + + + # statically link tlibs externals + #tlibs/file/loadinstr.cpp + tlibs/file/recent.cpp tlibs/file/x3d.cpp + tlibs/log/log.cpp tlibs/log/debug.cpp + tlibs/math/rand.cpp + tlibs/string/spec_char.cpp + tlibs/helper/flags.cpp tlibs/version.cpp +) + +target_link_libraries(takin + ${Boost_LIBRARIES} + Threads::Threads + Qt4::QtCore Qt4::QtGui Qt4::QtSvg #Qt4::QtOpenGL + ${PYTHON_LIBRARIES} + ${PNG_LIBRARIES} + ${QWT_LIBRARIES} + #${FREETYPE_LIBRARY} +) + + +# pre-build +add_custom_target(prebuild-script + COMMAND ${PROJECT_SOURCE_DIR}/prebuild.sh ${QT_UIC_EXECUTABLE} ${QT_MOC_EXECUTABLE} ${PROJECT_SOURCE_DIR} +) + + +# post-build +#add_custom_command(TARGET takin POST_BUILD +# COMMAND qcollectiongenerator ${PROJECT_SOURCE_DIR}/doc/takin.qhcp -o ${PROJECT_SOURCE_DIR}/doc/takin.qhc +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qhc ${PROJECT_SOURCE_DIR}/res/ +# && cp -v ${PROJECT_SOURCE_DIR}/doc/takin.qch ${PROJECT_SOURCE_DIR}/res/ +# MAIN_DEPENDENCY takin) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET takin POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY takin + ) +endif() + + +add_dependencies(takin prebuild-script) +add_dependencies(takin gentab) +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# convofit, convoseries +# ----------------------------------------------------------------------------- +add_executable(convofit + tools/res/cn.cpp tools/res/pop.cpp tools/res/eck.cpp tools/res/viol.cpp + #tools/res/simple.cpp + + tools/monteconvo/TASReso.cpp + tools/monteconvo/sqw.cpp tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwfactory.cpp + tools/monteconvo/sqw_py.cpp + + tools/convofit/convofit.cpp + tools/convofit/model.cpp tools/convofit/scan.cpp + + + # statically link tlibs externals + tlibs/log/log.cpp + tlibs/math/rand.cpp + #tlibs/file/loadinstr.cpp + #libs/globals.cpp +) + +set_target_properties(convofit PROPERTIES COMPILE_FLAGS "-DNO_QT") + +target_link_libraries(convofit + Threads::Threads + ${Boost_LIBRARIES} ${Minuit2_LIBRARIES} ${PYTHON_LIBRARIES} +) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET convofit POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY convofit + ) +endif() + +# ----------------------------------------------------------------------------- + +add_executable(convoseries + tools/convofit/scanseries.cpp + + # statically link tlibs externals + tlibs/log/log.cpp +) + +set_target_properties(convoseries PROPERTIES COMPILE_FLAGS "-DNO_QT") + +target_link_libraries(convoseries + ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} +) + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command(TARGET convoseries POST_BUILD + COMMAND strip -v $ + MAIN_DEPENDENCY convoseries + ) +endif() +# ----------------------------------------------------------------------------- + + + + +# ----------------------------------------------------------------------------- +# install +# ----------------------------------------------------------------------------- +install(TARGETS takin DESTINATION bin) +install(TARGETS convofit convoseries DESTINATION bin) +install(DIRECTORY ${PROJECT_SOURCE_DIR}/res ${PROJECT_SOURCE_DIR}/examples ${PROJECT_SOURCE_DIR}/doc + DESTINATION share/takin) +install(FILES ${PROJECT_SOURCE_DIR}/COPYING ${PROJECT_SOURCE_DIR}/AUTHORS ${PROJECT_SOURCE_DIR}/LICENSES + DESTINATION share/takin) +# ----------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 120000 index 0000000..e3d4bb4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1 @@ +CMakeLists-static.txt \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/FindClipper.cmake b/FindClipper.cmake new file mode 100644 index 0000000..f8c2551 --- /dev/null +++ b/FindClipper.cmake @@ -0,0 +1,23 @@ +find_path(Clipper_INCLUDE_DIRS + NAMES clipper.h + PATH_SUFFIXES clipper + HINTS /usr/include/clipper /usr/local/include/clipper /opt/local/include/clipper + DOC "Clipper include directories" +) + +find_library(Clipper_LIBRARIES + NAMES libclipper-core.so + HINTS /usr/lib64/ /usr/lib/ /usr/local/lib64 /usr/local/lib /opt/local/lib + DOC "Clipper library" +) + +if(Clipper_LIBRARIES) + set(Clipper_FOUND 1) + message("Clipper include directories: ${Clipper_INCLUDE_DIRS}") + message("Clipper library: ${Clipper_LIBRARIES}") +else() + set(Clipper_FOUND 0) + set(Clipper_INCLUDE_DIRS "") + set(Clipper_LIBRARIES "") + message("Error: Clipper could not be found!") +endif() diff --git a/Findtlibs.cmake b/Findtlibs.cmake new file mode 100644 index 0000000..0cdba0e --- /dev/null +++ b/Findtlibs.cmake @@ -0,0 +1,28 @@ +find_path(tlibs_INCLUDE_DIRS + NAMES version.h + PATH_SUFFIXES tlibs + HINTS /usr/include/tlibs /usr/local/include/tlibs /opt/local/include/tlibs + DOC "tlibs include directory" +) + +find_library(tlibs_LIBRARIES + NAMES libtlibs.so + HINTS /usr/lib64/ /usr/lib/ /usr/local/lib64 /usr/local/lib /opt/local/lib + DOC "tlibs library" +) + +find_path(tlibs_SHARED_DIRS + NAMES AUTHORS COPYING.GPLv2 COPYING.GPLv3 LICENSES FindMinuit2.cmake + HINTS /usr/share/tlibs /usr/local/share/tlibs /opt/local/share/tlibs + DOC "tlibs shared directory" +) + + +if(tlibs_LIBRARIES) + set(tlibs_FOUND 1) + message("tLibs include directories: ${tlibs_INCLUDE_DIRS}") + message("tLibs library: ${tlibs_LIBRARIES}") +else() + set(tlibs_FOUND 0) + message("Error: tLibs could not be found!") +endif() diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..653a667 --- /dev/null +++ b/INSTALL @@ -0,0 +1,47 @@ +Preparations before compilation +------------------------------- + + +Install (developer versions of) all required libraries either from your +system's package manager or directly from the given URLs: + * Boost: http://www.boost.org + * Qt 4: http://www.qt.io + * Qwt 6: http://qwt.sourceforge.net + * Clipper: http://www.ysbl.york.ac.uk/~cowtan/clipper/ + * Tlibs: + checkout tlibs submodule + OR: + use ./setup_tlibs.sh + and follow the instructions in the INSTALL file + in the ./tlibs/ subfolder + +Set up other external dependencies: + * ./setup_externals.sh + + +=============================================================================== + + +Building Takin +-------------- + + +Takin has to be compiled with a fully C++11 compliant compiler, e.g.: + * GCC version 4.8 or above + * Clang + +Select appropriate Make lists (standard: (1) native, dynamic): + * ./setup_makelists.sh + +Make using CMake: + * mkdir build + * cd build + * cmake .. + * make + * optional: make install (as root) + + +Run program with + * takin + * Or, in case tlibs is not found, + e.g.: LD_LIBRARY_PATH=/usr/local/lib takin diff --git a/LICENSES b/LICENSES new file mode 100644 index 0000000..88bb6e5 --- /dev/null +++ b/LICENSES @@ -0,0 +1,1071 @@ +Licenses for third-party software used in this software +======================================================= + + +-------------------------------------------------------------------------------- +Boost +URL: http://www.boost.org + +Copyright Beman Dawes, David Abrahams, 1998-2005. +Copyright Rene Rivera 2004-2007. + +License: +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Rescal +URL: https://www.ill.eu/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/#c4703 + +Copyright (C) 1998 Zinkin, McMorrow, Tennant, Farhi, and Wildes. + +License: GNU GPL version 2 (see below) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +McStas +URL: http://www.mcstas.org + +Copyright (C) Riso National Laboratory. +Authors: P. K. Willendrup, E. Knudsen, K. Lefmann, E. Farhi, U. Filges, + K. Nielsen, P. Astrand, K. Lieutenant, and P. Christiansen + +License: GNU GPL version 2 (see below) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Qt +URL: http://www.qt.io + +Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + +License: GNU LGPL version 2.1 or GNU GPL version 3.0 (see below) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Qwt +URL: http://qwt.sourceforge.net + +Copyright (C) 1997 Josef Wilgen +Copyright (C) 2002 Uwe Rathmann + +License: Qwt License Version 1.0 (modified GNU LGPL version 2.1) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +FreeType +URL: http://freetype.org + +Copyright (C) 1996-2002, 2006 by +David Turner, Robert Wilhelm, and Werner Lemberg + +License: GNU GPL version 2 (see below) or FreeType License +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Lapack & Lapacke +URL: http://www.netlib.org/lapack + +Copyright (c) 1992-2013 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. +Copyright (c) 2000-2013 The University of California Berkeley. All + rights reserved. +Copyright (c) 2006-2013 The University of Colorado Denver. All rights + reserved. + +License: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + +- Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +The copyright holders provide no reassurances that the source code +provided does not infringe any patent, copyright, or any other +intellectual property rights of third parties. The copyright holders +disclaim any liability to any recipient for claims brought against +recipient by any third party for infringement of that parties +intellectual property rights. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Clipper +URL: http://www.ysbl.york.ac.uk/~cowtan/clipper/ + +Copyright (c) 2000-2006 by Kevin Cowtan + +License: GNU LGPL version 2.1 (see below) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +NICOS +URL: http://forge.frm2.tum.de/cgit/cgit.cgi/frm2/nicos/nicos-core.git/ + +Copyright (c) 2009-2015 by the NICOS contributors + +License: GNU GPL version 2 (see below) +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Gnuplot +URL: http://www.gnuplot.info + +Copyright (C) 1986-1993, 1998, 2004, 2007-2014 +Thomas Williams, Colin Kelley and many others + +License: +Permission to use, copy, and distribute this software and its +documentation for any purpose with or without fee is hereby granted, +provided that the above copyright notice appear in all copies and +that both that copyright notice and this permission notice appear +in supporting documentation. + +Permission to modify the software is granted, but not the right to +distribute the complete modified source code. Modifications are to +be distributed as patches to the released version. Permission to +distribute binaries produced by compiling modified sources is granted, +provided you + 1. distribute the corresponding source modifications from the + released version in the form of a patch file along with the binaries, + 2. add special version identification to distinguish your version + in addition to the base release version number, + 3. provide your name and address as the primary contact for the + support of your modified version, and + 4. retain our contact information in regard to use of the base + software. +Permission to distribute the released version of the source code along +with corresponding source modifications in the form of a patch file is +granted with same provisions 2 through 4 for binary distributions. + +This software is provided "as is" without express or implied warranty +to the extent permitted by applicable law. +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Tango Icons +URL: http://tango.freedesktop.org/Tango_Icon_Library + +License: Public Domain +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Text of the GNU GPL version 2 (only pertaining to above-mentioned third-party +software products which use this license): +-------------------------------------------------------------------------------- + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. +-------------------------------------------------------------------------------- + + + +-------------------------------------------------------------------------------- +Text of the GNU LGPL version 2.1 (only pertaining to above-mentioned third-party +software products which use this license): +-------------------------------------------------------------------------------- + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! +-------------------------------------------------------------------------------- diff --git a/backup-src.sh b/backup-src.sh new file mode 100755 index 0000000..a3ed60b --- /dev/null +++ b/backup-src.sh @@ -0,0 +1,17 @@ +#!/bin/zsh +# quick backup of Takin source files +# @author tweber +# @date 18-jun-2016 + +thetime=${${${$(date --iso-8601='ns')//:/-}//,/_}//+/p} +thefile="takin_src-${thetime}.txz" + +find . \( -name "*.cpp" -type f \) -o \ + \( -name "*.h" -type f \) -o \ + \( -name "*.py" -type f \) -o \ + \( -name "*.scr" -type f \) -o \ + \( -name "*.sh" -type f \) -o \ + \( -name "*.ui" -type f \) \ + | xargs tar -Jvcf ${thefile} + +echo -e "\nWrote ${thefile}\n" diff --git a/bin/.dir b/bin/.dir new file mode 100644 index 0000000..9084031 --- /dev/null +++ b/bin/.dir @@ -0,0 +1 @@ +directory for binaries diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..2a94a4b --- /dev/null +++ b/build.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +MAKE=make +GCC=$(which gcc 2>/dev/null) + +if [ "$GCC" != "" ] # don't check version if only e.g. clang is available +then + GCC_VER=$($GCC -dumpversion) + echo -e "GCC is version $GCC_VER" + + GCC_VER=(${GCC_VER//./ }) + + if [ ${GCC_VER[0]} -le 4 ] && [ ${GCC_VER[1]} -lt 8 ] + then + echo -e "\t... which is not compatible with Takin.\n\t\tAt least version 4.8 is needed." + exit -1; + fi +fi + + + + +if [ ! -d tlibs ] || [ ! -f tlibs/AUTHORS ] +then + echo -e "Error: tlibs not installed. Use ./setup_tlibs.sh" + exit -1; +fi + + + + +echo -e "Prebuilding..." +if ! ./prebuild.sh +then + echo -e "Error: Prebuild failed"; + exit -1; +fi + + + + +NPROC=$(which nproc 2>/dev/null) +if [ "$NPROC" == "" ]; then NPROC="/usr/bin/nproc"; fi + + +if [ ! -x $NPROC ] +then + CPUCNT=2 +else + CPUCNT=$($NPROC --ignore=1) +fi + +echo -e "\nBuilding using $CPUCNT processes..." +${MAKE} -j${CPUCNT} -f themakefile diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..7443b0c --- /dev/null +++ b/clean.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo -e "Cleaning stuff made by themakefile..." +make -f themakefile clean + + +if [ -f Makefile ] +then + echo -e "\nCleaning stuff made by Makefile..." + make clean +fi + +rm -f CMakeCache.txt +rm -rf CMakeFiles + + +rm -f doc/takin.qch +rm -f doc/takin.qhc + + +# restore link +#rm takin +#ln -sf bin/takin diff --git a/convofit b/convofit new file mode 120000 index 0000000..4840990 --- /dev/null +++ b/convofit @@ -0,0 +1 @@ +bin/convofit \ No newline at end of file diff --git a/convoseries b/convoseries new file mode 120000 index 0000000..0be4498 --- /dev/null +++ b/convoseries @@ -0,0 +1 @@ +bin/convoseries \ No newline at end of file diff --git a/dialogs/AboutDlg.cpp b/dialogs/AboutDlg.cpp new file mode 100644 index 0000000..6ac5355 --- /dev/null +++ b/dialogs/AboutDlg.cpp @@ -0,0 +1,162 @@ +/* + * About Dialog + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#include "AboutDlg.h" + +#include +#include +#include +#include "tlibs/version.h" + +#include "tlibs/string/string.h" +#include "libs/formfactors/formfact.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/globals.h" +#include "libs/version.h" +#include + + +AboutDlg::AboutDlg(QWidget* pParent, QSettings *pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + + if(m_pSettings->contains("about/geo")) + restoreGeometry(m_pSettings->value("about/geo").toByteArray()); + } + + labelVersion->setText("Version " TAKIN_VER); + labelWritten->setText("Written by Tobias Weber "); + labelYears->setText("2014 - 2016"); + + std::string strCC = "Built using " + std::string(BOOST_COMPILER); +#ifdef __cplusplus + strCC += " (standard: " + tl::var_to_str(__cplusplus) + ")"; +#endif +#ifdef BOOST_STDLIB + strCC += " with " + std::string(BOOST_STDLIB); +#endif +#ifdef BOOST_PLATFORM + strCC += " for " + std::string(BOOST_PLATFORM); +#endif + strCC += "."; + labelCC->setText(strCC.c_str()); + labelBuildDate->setText(QString("Build date: ") + + QString(__DATE__) + ", " + QString(__TIME__)); + + + // ------------------------------------------------------------------------- + + + std::ostringstream ostrLibs; + ostrLibs << ""; + + ostrLibs << "
"; + + ostrLibs << "
Uses Qt version " << QT_VERSION_STR << "
"; + ostrLibs << "
http://qt-project.org
"; + + ostrLibs << "
Uses Qwt version " << QWT_VERSION_STR << "
"; + ostrLibs << "
http://qwt.sourceforge.net
"; + + std::string strBoost = BOOST_LIB_VERSION; + tl::find_all_and_replace(strBoost, "_", "."); + ostrLibs << "
Uses Boost version " << strBoost << "
"; + ostrLibs << "
http://www.boost.org
"; + +#ifndef NO_LAPACK + ostrLibs << "
Uses Lapack/e version 3
"; + ostrLibs << "
http://www.netlib.org/lapack
"; +#endif + + ostrLibs << "
Uses tLibs version " << TLIBS_VERSION << "
"; + + ostrLibs << "
Uses Clipper crystallography library
"; + ostrLibs << "
http://www.ysbl.york.ac.uk/~cowtan/clipper
"; + + ostrLibs << "
Uses resolution algorithms ported from Rescal version 5
"; + ostrLibs << "
http://www.ill.eu/en/html/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab
"; + + ostrLibs << "
Uses Tango icons
"; + ostrLibs << "
http://tango.freedesktop.org
"; + + ostrLibs << "
"; + //ostrLibs << "

See the LICENSES file in the Takin root directory.

"; + ostrLibs << ""; + + labelLibraries->setText(ostrLibs.str().c_str()); + + + // ------------------------------------------------------------------------- + + + std::ostringstream ostrConst; + ostrConst << ""; + + ostrConst << "
"; + + ostrConst << "
Physical constants from Boost Units
"; + ostrConst << "
http://www.boost.org/doc/libs/release/libs/units/
"; + + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + ostrConst << "
" << sgs->get_sgsource(0) <<"
"; + ostrConst << "
get_sgsource(1) << "\">" << sgs->get_sgsource(1) << "
"; + + std::shared_ptr> ff = FormfactList::GetInstance(); + std::shared_ptr> mff = MagFormfactList::GetInstance(); + std::shared_ptr> sl = ScatlenList::GetInstance(); + + if(g_bHasFormfacts) + { + ostrConst << "
" << ff->GetSource() << "
"; + ostrConst << "
GetSourceUrl() << "\">" << ff->GetSourceUrl() << "
"; + } + if(g_bHasMagFormfacts) + { + ostrConst << "
" << mff->GetSource() << "
"; + ostrConst << "
GetSourceUrl() << "\">" << mff->GetSourceUrl() << "
"; + } + if(g_bHasScatlens) + { + ostrConst << "
" << sl->GetSource() << "
"; + ostrConst << "
GetSourceUrl() << "\">" << sl->GetSourceUrl() << "
"; + } + + ostrConst << "
"; + ostrConst << ""; + labelConst->setText(ostrConst.str().c_str()); + + + + std::string strLicensesFile = find_resource("LICENSES"); + std::ifstream ifstrLicenses(strLicensesFile); + std::string strLicenses; + while(ifstrLicenses) + { + std::string strLic; + std::getline(ifstrLicenses, strLic); + strLicenses += strLic + "\n"; + } + editAllLicenses->setPlainText(strLicenses.c_str()); +} + + +void AboutDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("about/geo", saveGeometry()); + + QDialog::accept(); +} + + +#include "AboutDlg.moc" diff --git a/dialogs/AboutDlg.h b/dialogs/AboutDlg.h new file mode 100644 index 0000000..46839e5 --- /dev/null +++ b/dialogs/AboutDlg.h @@ -0,0 +1,27 @@ +/* + * About Dialog + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#ifndef __ABOUT_DLG_H__ +#define __ABOUT_DLG_H__ + +#include +#include +#include "ui/ui_about.h" + +class AboutDlg : public QDialog, Ui::AboutDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + + virtual void accept() override; + + public: + AboutDlg(QWidget* pParent=0, QSettings *pSett=0); + virtual ~AboutDlg() = default; +}; + +#endif diff --git a/dialogs/AtomsDlg.cpp b/dialogs/AtomsDlg.cpp new file mode 100644 index 0000000..ff77d26 --- /dev/null +++ b/dialogs/AtomsDlg.cpp @@ -0,0 +1,183 @@ +/** + * Atom Positions Dialog + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#include "AtomsDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/math/linalg.h" + +using t_real = t_real_glob; + + +enum class AtInfo : int +{ + NAME = 0, + POS_X = 1, + POS_Y = 2, + POS_Z = 3, + + J = 4 +}; + +AtomsDlg::AtomsDlg(QWidget* pParent, QSettings *pSettings, bool bEnableJ) + : QDialog(pParent), m_pSettings(pSettings), m_bEnableJ(bEnableJ) +{ + setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + if(m_bEnableJ) + { + tableAtoms->setColumnCount(5); + tableAtoms->setHorizontalHeaderItem(static_cast(AtInfo::J), new QTableWidgetItem("J (meV/K)")); } + + tableAtoms->setColumnWidth(0, 75); + btnAdd->setIcon(load_icon("res/list-add.svg")); + btnDel->setIcon(load_icon("res/list-remove.svg")); + +#if QT_VER >= 5 + QObject::connect(btnAdd, &QAbstractButton::clicked, this, &AtomsDlg::AddAtom); + QObject::connect(btnDel, &QAbstractButton::clicked, this, &AtomsDlg::RemoveAtom); + QObject::connect(buttonBox, &QDialogButtonBox::clicked, this, &AtomsDlg::ButtonBoxClicked); +#else + QObject::connect(btnAdd, SIGNAL(clicked(bool)), this, SLOT(AddAtom())); + QObject::connect(btnDel, SIGNAL(clicked(bool)), this, SLOT(RemoveAtom())); + QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, + SLOT(ButtonBoxClicked(QAbstractButton*))); +#endif + + if(m_pSettings && m_pSettings->contains("atoms/geo")) + restoreGeometry(m_pSettings->value("atoms/geo").toByteArray()); +} + +AtomsDlg::~AtomsDlg() {} + + +void AtomsDlg::RemoveAtom() +{ + const bool bSort = tableAtoms->isSortingEnabled(); + tableAtoms->setSortingEnabled(0); + + bool bNothingRemoved = 1; + + // remove selected rows + QList lstSel = tableAtoms->selectedRanges(); + for(QTableWidgetSelectionRange& range : lstSel) + { + //std::cout << range.bottomRow() << " " << range.topRow() << std::endl; + for(int iRow=range.bottomRow(); iRow>=range.topRow(); --iRow) + { + tableAtoms->removeRow(iRow); + bNothingRemoved = 0; + } + } + + // remove last row if nothing is selected + if(bNothingRemoved) + tableAtoms->removeRow(tableAtoms->rowCount()-1); + + tableAtoms->setSortingEnabled(bSort); +} + +void AtomsDlg::AddAtom() +{ + const bool bSort = tableAtoms->isSortingEnabled(); + tableAtoms->setSortingEnabled(0); + + int iRow = tableAtoms->rowCount(); + tableAtoms->insertRow(iRow); + tableAtoms->setItem(iRow, 0, new QTableWidgetItem("H")); + for(unsigned int i=0; i<3; ++i) + tableAtoms->setItem(iRow, static_cast(AtInfo::POS_X)+i, new QTableWidgetItem("0")); + if(m_bEnableJ) + tableAtoms->setItem(iRow, static_cast(AtInfo::J), new QTableWidgetItem("0")); + + tableAtoms->setSortingEnabled(bSort); +} + + +void AtomsDlg::SetAtoms(const std::vector>& vecAtoms) +{ + const bool bSort = tableAtoms->isSortingEnabled(); + tableAtoms->setSortingEnabled(0); + + tableAtoms->setRowCount(vecAtoms.size()); + + for(std::size_t iRow=0; iRowcolumnCount(); ++iCol) + if(!tableAtoms->item(iRow, iCol)) + tableAtoms->setItem(iRow, iCol, new QTableWidgetItem("")); + + const AtomPos& atom = vecAtoms[iRow]; + tableAtoms->item(iRow, 0)->setText(atom.strAtomName.c_str()); + for(unsigned int i=0; i<3; ++i) + tableAtoms->item(iRow, static_cast(AtInfo::POS_X)+i)->setText(tl::var_to_str(atom.vecPos[i]).c_str()); + + if(m_bEnableJ) + tableAtoms->item(iRow, static_cast(AtInfo::J))->setText(tl::var_to_str(atom.J).c_str()); + } + + tableAtoms->setSortingEnabled(bSort); +} + +void AtomsDlg::SendApplyAtoms() +{ + std::vector> vecAtoms; + vecAtoms.reserve(tableAtoms->rowCount()); + + for(int iRow=0; iRowrowCount(); ++iRow) + { + AtomPos atom; + atom.strAtomName = tableAtoms->item(iRow, static_cast(AtInfo::NAME))->text().toStdString(); + tl::trim(atom.strAtomName); + t_real dX = tl::str_to_var(tableAtoms->item(iRow, static_cast(AtInfo::POS_X))->text().toStdString()); + t_real dY = tl::str_to_var(tableAtoms->item(iRow, static_cast(AtInfo::POS_Y))->text().toStdString()); + t_real dZ = tl::str_to_var(tableAtoms->item(iRow, static_cast(AtInfo::POS_Z))->text().toStdString()); + atom.vecPos = tl::make_vec({dX, dY, dZ}); + + if(m_bEnableJ) + atom.J = tl::str_to_var(tableAtoms->item(iRow, static_cast(AtInfo::J))->text().toStdString()); + + vecAtoms.push_back(std::move(atom)); + } + + emit ApplyAtoms(vecAtoms); +} + +void AtomsDlg::ButtonBoxClicked(QAbstractButton* pBtn) +{ + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ApplyRole || + buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + SendApplyAtoms(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::RejectRole) + { + reject(); + } + + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + if(m_pSettings) + m_pSettings->setValue("atoms/geo", saveGeometry()); + + QDialog::accept(); + } +} + +void AtomsDlg::closeEvent(QCloseEvent* pEvt) +{ + QDialog::closeEvent(pEvt); +} + + +#include "AtomsDlg.moc" diff --git a/dialogs/AtomsDlg.h b/dialogs/AtomsDlg.h new file mode 100644 index 0000000..e9e9704 --- /dev/null +++ b/dialogs/AtomsDlg.h @@ -0,0 +1,53 @@ +/* + * Atom Positions Dialog + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_ATOMS_DLG_H__ +#define __TAKIN_ATOMS_DLG_H__ + +#include +#include +#include +#include +#include + +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "libs/spacegroups/latticehelper.h" + +#include "ui/ui_atoms.h" +namespace ublas = boost::numeric::ublas; + + + +class AtomsDlg : public QDialog, Ui::AtomsDlg +{ Q_OBJECT +protected: + QSettings *m_pSettings = nullptr; + bool m_bEnableJ = 0; + +protected: + virtual void closeEvent(QCloseEvent*) override; + void SendApplyAtoms(); + +protected slots: + void ButtonBoxClicked(QAbstractButton* pBtn); + void RemoveAtom(); + void AddAtom(); + +public: + AtomsDlg(QWidget* pParent = nullptr, QSettings *pSettings = nullptr, + bool bEnableJ=0); + virtual ~AtomsDlg(); + + void SetAtoms(const std::vector>& vecAtoms); + +signals: + void ApplyAtoms(const std::vector>& vecAtoms); +}; + + +#endif diff --git a/dialogs/DWDlg.cpp b/dialogs/DWDlg.cpp new file mode 100644 index 0000000..e903553 --- /dev/null +++ b/dialogs/DWDlg.cpp @@ -0,0 +1,310 @@ +/* + * Scattering factors dialog (e.g. Debye-Waller factor) + * @author tweber + * @date 2013, jan-2015 + * @license GPLv2 + */ + +#include "DWDlg.h" + +#include "tlibs/string/string.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/atoms.h" +#include "tlibs/helper/array.h" + +#include + +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_angle_si rads = tl::get_one_radian(); +static const tl::t_temperature_si kelvin = tl::get_one_kelvin(); + + +DWDlg::DWDlg(QWidget* pParent, QSettings *pSettings) + : QDialog(pParent), m_pSettings(pSettings) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + + // ------------------------------------------------------------------------- + // Bose Factor stuff + std::vector vecSpinBoxesBose = {spinBoseT, spinBoseEMin, spinBoseEMax}; + for(QDoubleSpinBox* pSpin : vecSpinBoxesBose) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(CalcBose())); + + m_plotwrapBose.reset(new QwtPlotWrapper(plotBose, 2)); + + // positive Bose factor + QPen penCurveBosePos; + penCurveBosePos.setColor(QColor(0,0,0x99)); + penCurveBosePos.setWidth(2); + m_plotwrapBose->GetCurve(0)->setTitle("Boson Creation"); + m_plotwrapBose->GetCurve(0)->setPen(penCurveBosePos); + + // negative Bose factor + QPen penCurveBoseNeg; + penCurveBoseNeg.setColor(QColor(0x99,0,0)); + penCurveBoseNeg.setWidth(2); + m_plotwrapBose->GetCurve(1)->setTitle("Boson Annihilation"); + m_plotwrapBose->GetCurve(1)->setPen(penCurveBoseNeg); + + if(m_plotwrapBose->HasTrackerSignal()) + connect(m_plotwrapBose->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + m_pLegendBose = new QwtLegend(); + m_plotwrapBose->GetPlot()->insertLegend(m_pLegendBose, QwtPlot::TopLegend); + + m_plotwrapBose->GetPlot()->setAxisTitle(QwtPlot::xBottom, "E (meV)"); + m_plotwrapBose->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Bose Factor"); + + CalcBose(); + + + // ------------------------------------------------------------------------- + // DW Factor stuff + std::vector vecSpinBoxes = {spinAMU_deb, spinTD_deb, spinT_deb, spinMinQ_deb, spinMaxQ_deb}; + for(QDoubleSpinBox* pSpin : vecSpinBoxes) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(CalcDW())); + + m_plotwrapDW.reset(new QwtPlotWrapper(plot, 1)); + m_plotwrapDW->GetCurve(0)->setTitle("Debye-Waller Factor"); + + if(m_plotwrapDW->HasTrackerSignal()) + connect(m_plotwrapDW->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + m_plotwrapDW->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Q (1/A)"); + m_plotwrapDW->GetPlot()->setAxisTitle(QwtPlot::yLeft, "DW Factor"); + + CalcDW(); + + + // ------------------------------------------------------------------------- + // Ana Factor stuff + std::vector vecSpinBoxesAna = {spinAnad, spinMinkf, spinMaxkf}; + for(QDoubleSpinBox* pSpin : vecSpinBoxesAna) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(CalcAna())); + + m_plotwrapAna.reset(new QwtPlotWrapper(plotAna, 1)); + m_plotwrapAna->GetCurve(0)->setTitle("Analyser Factor"); + + if(m_plotwrapAna->HasTrackerSignal()) + connect(m_plotwrapAna->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + m_plotwrapAna->GetPlot()->setAxisTitle(QwtPlot::xBottom, "kf (1/A)"); + m_plotwrapAna->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Intensity (a.u.)"); + + CalcAna(); + + + // ------------------------------------------------------------------------- + // Lorentz Factor stuff + std::vector vecSpinBoxesLor = {spinMin2Th, spinMax2Th}; + for(QDoubleSpinBox* pSpin : vecSpinBoxesLor) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(CalcLorentz())); + QObject::connect(checkPol, SIGNAL(toggled(bool)), this, SLOT(CalcLorentz())); + + m_plotwrapLor.reset(new QwtPlotWrapper(plotLorentz, 1)); + m_plotwrapLor->GetCurve(0)->setTitle("Lorentz Factor"); + + if(m_plotwrapLor->HasTrackerSignal()) + connect(m_plotwrapLor->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + m_plotwrapLor->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Scattering Angle (deg)"); + m_plotwrapLor->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Lorentz Factor"); + + CalcLorentz(); + + + if(m_pSettings && m_pSettings->contains("dw/geo")) + restoreGeometry(m_pSettings->value("dw/geo").toByteArray()); +} + + +DWDlg::~DWDlg() +{} + +void DWDlg::cursorMoved(const QPointF& pt) +{ + std::string strX = tl::var_to_str(pt.x(), g_iPrecGfx); + std::string strY = tl::var_to_str(pt.y(), g_iPrecGfx); + + std::ostringstream ostr; + ostr << "(" << strX << ", " << strY << ")"; + + this->labelStatus->setText(ostr.str().c_str()); +} + + +void DWDlg::CalcBose() +{ + const unsigned int NUM_POINTS = 512; + + const t_real dMinE = spinBoseEMin->value(); + const t_real dMaxE = spinBoseEMax->value(); + + const tl::t_temperature_si T = t_real(spinBoseT->value()) * kelvin; + + m_vecBoseE.clear(); + m_vecBoseIntPos.clear(); + m_vecBoseIntNeg.clear(); + + m_vecBoseE.reserve(NUM_POINTS); + m_vecBoseIntPos.reserve(NUM_POINTS); + m_vecBoseIntNeg.reserve(NUM_POINTS); + + for(unsigned int iPt=0; iPt E = (dMinE + (dMaxE - dMinE)/t_real(NUM_POINTS)*t_real(iPt)) * meV; + m_vecBoseE.push_back(E / meV); + + m_vecBoseIntPos.push_back(tl::bose(E, T)); + m_vecBoseIntNeg.push_back(tl::bose(-E, T)); + } + + set_qwt_data()(*m_plotwrapBose, m_vecBoseE, m_vecBoseIntPos, 0, false); + set_qwt_data()(*m_plotwrapBose, m_vecBoseE, m_vecBoseIntNeg, 1, false); + + std::vector vecMerged; + vecMerged.resize(m_vecBoseIntPos.size() + m_vecBoseIntNeg.size()); + std::merge(m_vecBoseIntPos.begin(), m_vecBoseIntPos.end(), + m_vecBoseIntNeg.begin(), m_vecBoseIntNeg.end(), vecMerged.begin()); + set_zoomer_base(m_plotwrapBose->GetZoomer(), + tl::container_cast()(m_vecBoseE), + tl::container_cast()(vecMerged)); + + m_plotwrapBose->GetPlot()->replot(); +} + + +void DWDlg::CalcLorentz() +{ + const unsigned int NUM_POINTS = 512; + + const t_real dMin2th = tl::d2r(spinMin2Th->value()); + const t_real dMax2th = tl::d2r(spinMax2Th->value()); + + const bool bPol = checkPol->isChecked(); + + m_vecLor2th.clear(); + m_vecLor.clear(); + + m_vecLor2th.reserve(NUM_POINTS); + m_vecLor.reserve(NUM_POINTS); + + for(unsigned int iPt=0; iPt()(*m_plotwrapLor, m_vecLor2th, m_vecLor, 0, true); +} + + +void DWDlg::CalcDW() +{ + const unsigned int NUM_POINTS = 512; + + t_real dMinQ = spinMinQ_deb->value(); + t_real dMaxQ = spinMaxQ_deb->value(); + + tl::t_temperature_si T = t_real(spinT_deb->value()) * kelvin; + tl::t_temperature_si T_D = t_real(spinTD_deb->value()) * kelvin; + tl::t_mass_si M = t_real(spinAMU_deb->value()) * tl::get_amu(); + + m_vecQ.clear(); + m_vecDeb.clear(); + + m_vecQ.reserve(NUM_POINTS); + m_vecDeb.reserve(NUM_POINTS); + + bool bHasZetaSq = 0; + for(unsigned int iPt=0; iPt Q = (dMinQ + (dMaxQ - dMinQ)/t_real(NUM_POINTS)*t_real(iPt)) / angs; + t_real dDWF = 0.; + auto zetasq = angs*angs; + + if(T <= T_D) + dDWF = tl::debye_waller_low_T(T_D, T, M, Q, &zetasq); + else + dDWF = tl::debye_waller_high_T(T_D, T, M, Q, &zetasq); + + m_vecQ.push_back(Q * angs); + + if(!bHasZetaSq) + { + std::string strZetaSq = tl::var_to_str(t_real(tl::my_units_sqrt>(zetasq) / angs)); + editZetaSq->setText(strZetaSq.c_str()); + + bHasZetaSq = 1; + } + + m_vecDeb.push_back(dDWF); + } + + set_qwt_data()(*m_plotwrapDW, m_vecQ, m_vecDeb, 0, true); +} + + +void DWDlg::CalcAna() +{ + const unsigned int NUM_POINTS = 512; + + const tl::t_length_si d = t_real(spinAnad->value()) * angs; + const t_real dMinKf = spinMinkf->value(); + const t_real dMaxKf = spinMaxkf->value(); + + t_real dAngMax = 0.5*tl::r2d(tl::get_mono_twotheta(dMinKf/angs, d, 1) / rads); + t_real dAngMin = 0.5*tl::r2d(tl::get_mono_twotheta(dMaxKf/angs, d, 1) / rads); + + editAngMin->setText(tl::var_to_str(dAngMin).c_str()); + editAngMax->setText(tl::var_to_str(dAngMax).c_str()); + + m_veckf.clear(); + m_vecInt.clear(); + + m_veckf.reserve(NUM_POINTS); + m_vecInt.reserve(NUM_POINTS); + + for(unsigned int iPt=0; iPt kf = (dMinKf + (dMaxKf - dMinKf)/t_real(NUM_POINTS)*t_real(iPt)) / angs; + t_real dEffic = tl::ana_effic_factor(kf, d); + + m_veckf.push_back(kf * angs); + m_vecInt.push_back(dEffic); + } + + set_qwt_data()(*m_plotwrapAna, m_veckf, m_vecInt, 0, true); +} + + +void DWDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + +void DWDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("dw/geo", saveGeometry()); + + QDialog::accept(); +} + + +#include "DWDlg.moc" + diff --git a/dialogs/DWDlg.h b/dialogs/DWDlg.h new file mode 100644 index 0000000..b5dcea0 --- /dev/null +++ b/dialogs/DWDlg.h @@ -0,0 +1,60 @@ +/* + * Scattering factors dialog (e.g. Debye-Waller factor) + * @author tweber + * @date 2013, jan-2015 + * @license GPLv2 + */ + +#ifndef __DWDLG_H__ +#define __DWDLG_H__ + +#include +#include +#include "ui/ui_dw.h" + +#include +#include +#include "libs/qthelper.h" +#include "libs/globals.h" +#include + + +class DWDlg : public QDialog, Ui::DWDlg +{ Q_OBJECT +protected: + QSettings *m_pSettings = nullptr; + + // dw stuff + std::vector m_vecQ, m_vecDeb; + std::unique_ptr m_plotwrapDW; + + // ana stuff + std::vector m_veckf, m_vecInt; + std::unique_ptr m_plotwrapAna; + + // bose stuff + std::vector m_vecBoseE, m_vecBoseIntPos, m_vecBoseIntNeg; + std::unique_ptr m_plotwrapBose; + QwtLegend *m_pLegendBose = nullptr; + + // lorentz stuff + std::vector m_vecLor2th, m_vecLor; + std::unique_ptr m_plotwrapLor; + +protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + +protected slots: + void cursorMoved(const QPointF& pt); + void CalcDW(); + void CalcAna(); + void CalcBose(); + void CalcLorentz(); + +public: + DWDlg(QWidget* pParent = nullptr, QSettings *pSettings = nullptr); + virtual ~DWDlg(); +}; + +#endif diff --git a/dialogs/DispDlg.cpp b/dialogs/DispDlg.cpp new file mode 100644 index 0000000..d8fbfd3 --- /dev/null +++ b/dialogs/DispDlg.cpp @@ -0,0 +1,617 @@ +/** + * Dispersion Dialog + * @author Tobias Weber + * @date may-2016 + * @license GPLv2 + */ + +#include "DispDlg.h" + +#include "tlibs/math/lattice.h" +#include "tlibs/math/atoms.h" +#include "tlibs/math/nn.h" +#include "tlibs/math/mag.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/linalg.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" +#include "libs/formfactors/formfact.h" +#include "libs/qthelper.h" + +#include +#include + +#include +#include + +using t_real = t_real_glob; +static const auto one_meV = tl::get_one_meV(); +static const auto kelvin = tl::get_one_kelvin(); +static const auto k_B = tl::get_kB(); + +namespace ublas = boost::numeric::ublas; +namespace algo = boost::algorithm; + +using t_mat = ublas::matrix; +using t_vec = ublas::vector; +using t_cplx = std::complex; + +#define TABLE_NN_ORDER 0 +#define TABLE_NN_ATOM 1 +#define TABLE_NN_X 2 +#define TABLE_NN_Y 3 +#define TABLE_NN_Z 4 +#define TABLE_NN_DIST 5 + +DispDlg::DispDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett), + m_pmapSpaceGroups(SpaceGroups::GetInstance()->get_space_groups()) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + btnSave->setIcon(load_icon("res/document-save.svg")); + btnLoad->setIcon(load_icon("res/document-open.svg")); + + + //tableNN->sortByColumn(TABLE_NN_ORDER); + tableNN->sortItems(TABLE_NN_ORDER); + tableNN->verticalHeader()->setDefaultSectionSize(tableNN->verticalHeader()->defaultSectionSize()*0.8); + tableNN->horizontalHeader()->setVisible(true); + tableNN->setColumnWidth(TABLE_NN_ORDER, 75); + tableNN->setColumnWidth(TABLE_NN_ATOM, 75); + tableNN->setColumnWidth(TABLE_NN_X, 75); + tableNN->setColumnWidth(TABLE_NN_Y, 75); + tableNN->setColumnWidth(TABLE_NN_Z, 75); + tableNN->setColumnWidth(TABLE_NN_DIST, 75); + + + m_plotwrapFerro.reset(new QwtPlotWrapper(plotFerro)); + m_plotwrapFerro->GetCurve(0)->setTitle("Ferromagnetic Dispersion"); + m_plotwrapFerro->GetPlot()->setAxisTitle(QwtPlot::xBottom, "q (rlu)"); + m_plotwrapFerro->GetPlot()->setAxisTitle(QwtPlot::yLeft, "E (meV)"); + if(m_plotwrapFerro->HasTrackerSignal()) + connect(m_plotwrapFerro->GetPicker(), SIGNAL(moved(const QPointF&)), + this, SLOT(cursorMoved(const QPointF&))); + + + spinCentreIdx->setMinimum(0); + + + std::vector vecEditsUC = {editA, editB, editC, editAlpha, editBeta, editGamma}; + for(QLineEdit* pEdit : vecEditsUC) + { + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CheckCrystalType())); + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(Calc())); + } + + QObject::connect(editEpsShell, SIGNAL(textEdited(const QString&)), this, SLOT(Calc())); + + QObject::connect(editSpaceGroupsFilter, SIGNAL(textChanged(const QString&)), this, SLOT(RepopulateSpaceGroups())); + QObject::connect(comboSpaceGroups, SIGNAL(currentIndexChanged(int)), this, SLOT(SpaceGroupChanged())); + + QObject::connect(editS, SIGNAL(textChanged(const QString&)), this, SLOT(Calc())); + + std::vector vecSpins = {spinNN, spinSC, spinCentreIdx}; + for(QSpinBox* pSpin : vecSpins) + QObject::connect(pSpin, SIGNAL(valueChanged(int)), this, SLOT(Calc())); + + QObject::connect(btnSave, SIGNAL(clicked()), this, SLOT(Save())); + QObject::connect(btnLoad, SIGNAL(clicked()), this, SLOT(Load())); + QObject::connect(btnAtoms, SIGNAL(clicked()), this, SLOT(ShowAtomDlg())); + + m_bDontCalc = 0; + RepopulateSpaceGroups(); + Calc(); + + setAcceptDrops(1); + + if(m_pSettings && m_pSettings->contains("disp/geo")) + restoreGeometry(m_pSettings->value("disp/geo").toByteArray()); +} + +DispDlg::~DispDlg() {} + + +void DispDlg::Calc() +{ + if(m_bDontCalc) return; + try + { + if(m_vecAtoms.size() == 0) + { + tl::log_err("No atoms defined."); + return; + } + + const t_real dEpsShell = editEpsShell->text().toDouble(); + + const t_real dA = editA->text().toDouble(); + const t_real dB = editB->text().toDouble(); + const t_real dC = editC->text().toDouble(); + const t_real dAlpha = tl::d2r(editAlpha->text().toDouble()); + const t_real dBeta = tl::d2r(editBeta->text().toDouble()); + const t_real dGamma = tl::d2r(editGamma->text().toDouble()); + + const t_real dS = editS->text().toDouble(); + const int iNN = spinNN->value(); + const int iSC = spinSC->value(); + int iIdxCentre = spinCentreIdx->value(); + if(iIdxCentre >= int(m_vecAtoms.size())) iIdxCentre = int(m_vecAtoms.size())-1; + if(iIdxCentre < 0) iIdxCentre = 0; + + // lattice + tl::Lattice lattice(dA, dB, dC, dAlpha, dBeta, dGamma); + tl::Lattice recip = lattice.GetRecip(); + + const t_mat matA = lattice.GetMetric(); + const t_mat matB = recip.GetMetric(); + + t_vec vecCentre = tl::mult(matA, m_vecAtoms[iIdxCentre].vecPos); + if(tl::is_nan_or_inf(vecCentre)) + { + tl::log_err("Invalid centre."); + return; + } + //tl::log_debug("Centre: ", vecCentre); + + + // spacegroup + const SpaceGroup *pSpaceGroup = GetCurSpaceGroup(); + if(!pSpaceGroup) + { + tl::log_err("No spacegroup defined."); + return; + } + const std::vector& vecSymTrafos = pSpaceGroup->GetTrafos(); + + + // all primitive atoms + std::vector vecAtoms, vecAtomsUC, vecAtomsSC, vecAtomsNN; + std::vector vecJ, vecJUC, vecJSC, vecJNN; + for(const AtomPos& atom : m_vecAtoms) + { + vecAtoms.push_back(atom.vecPos); + vecJ.push_back(atom.J * t_real(k_B / one_meV * kelvin)); + } + + // all atoms in unit cell + std::vector vecIdxUC, vecIdxSC; + std::tie(std::ignore, vecAtomsUC, std::ignore, vecIdxUC) = + tl::generate_all_atoms + (vecSymTrafos, vecAtoms, nullptr, matA, + t_real(-0.5), t_real(0.5), g_dEps); + for(std::size_t iIdxUC : vecIdxUC) + vecJUC.push_back(vecJ[iIdxUC]); + + + // all atoms in super cell + std::tie(vecAtomsSC, vecJSC, vecIdxSC) = + tl::generate_supercell + (lattice, vecAtomsUC, vecJUC, iSC); + std::vector vecNamesSC; + for(std::size_t iIdxSC : vecIdxSC) + vecNamesSC.push_back(m_vecAtoms[vecIdxUC[iIdxSC]].strAtomName); + + //for(std::size_t iAtom=0; iAtom> vecIdxNN = + tl::get_neighbours + (vecAtomsSC, vecCentre, dEpsShell); + std::size_t iNumRows = 0; + for(const auto& vecIdxNNInner : vecIdxNN) iNumRows += vecIdxNNInner.size(); + + + //---------------------------------------------------------------------- + // neighbours & table + const bool bSortTable = tableNN->isSortingEnabled(); + tableNN->setSortingEnabled(0); + tableNN->setRowCount(iNumRows); + + int iRow = 0; + std::size_t iOuterIdx = 0; + for(const auto& vecIdxNNInner : vecIdxNN) + { + for(std::size_t iIdx : vecIdxNNInner) + { + const t_vec& vecThisAtom = vecAtomsSC[iIdx]; + const t_cplx& cplxThisJ = vecJSC[iIdx]; + const std::string& strThisAtom = vecNamesSC[iIdx]; + + if(iOuterIdx > 0 && int(iOuterIdx) <= iNN) + { + vecAtomsNN.push_back(vecThisAtom - vecCentre); + vecJNN.push_back(cplxThisJ); + } + + if(!tableNN->item(iRow, TABLE_NN_ATOM)) + tableNN->setItem(iRow, TABLE_NN_ATOM, new QTableWidgetItem()); + if(!tableNN->item(iRow, TABLE_NN_ORDER)) + tableNN->setItem(iRow, TABLE_NN_ORDER, new QTableWidgetItemWrapper()); + if(!tableNN->item(iRow, TABLE_NN_X)) + tableNN->setItem(iRow, TABLE_NN_X, new QTableWidgetItemWrapper()); + if(!tableNN->item(iRow, TABLE_NN_Y)) + tableNN->setItem(iRow, TABLE_NN_Y, new QTableWidgetItemWrapper()); + if(!tableNN->item(iRow, TABLE_NN_Z)) + tableNN->setItem(iRow, TABLE_NN_Z, new QTableWidgetItemWrapper()); + if(!tableNN->item(iRow, TABLE_NN_DIST)) + tableNN->setItem(iRow, TABLE_NN_DIST, new QTableWidgetItemWrapper()); + + tableNN->item(iRow, TABLE_NN_ATOM)->setText(strThisAtom.c_str()); + dynamic_cast*>( + tableNN->item(iRow, TABLE_NN_ORDER))->SetValue(iOuterIdx); + dynamic_cast*>( + tableNN->item(iRow, TABLE_NN_X))->SetValue(vecThisAtom[0]); + dynamic_cast*>( + tableNN->item(iRow, TABLE_NN_Y))->SetValue(vecThisAtom[1]); + dynamic_cast*>( + tableNN->item(iRow, TABLE_NN_Z))->SetValue(vecThisAtom[2]); + dynamic_cast*>( + tableNN->item(iRow, TABLE_NN_DIST))->SetValue(ublas::norm_2(vecThisAtom - vecCentre)); + + ++iRow; + } + ++iOuterIdx; + } + + //for(const auto& vec : vecAtomsNN) std::cout << vec << std::endl; + //for(const auto& vec : vecJNN) std::cout << vec << std::endl; + + tableNN->setSortingEnabled(bSortTable); + labStatus->setText("OK."); + + + // --------------------------------------------------------------------- + // ferro plot + const std::size_t NUM_POINTS = 512; + m_vecFerroQ.clear(); + m_vecFerroE.clear(); + m_vecFerroQ.reserve(NUM_POINTS); + m_vecFerroE.reserve(NUM_POINTS); + + for(std::size_t iPt=0; iPt({1.,0.,0.}) * tPos; + t_vec vecq_AA = tl::mult(matB, vecq); + t_real dE = tl::ferromag + (vecAtomsNN, vecJNN, vecq_AA, dS); + + m_vecFerroQ.push_back(ublas::norm_2(vecq)); + m_vecFerroE.push_back(dE); + } + + set_qwt_data()(*m_plotwrapFerro, m_vecFerroQ, m_vecFerroE); + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + } +} + + +const SpaceGroup* DispDlg::GetCurSpaceGroup() const +{ + SpaceGroup *pSpaceGroup = 0; + int iSpaceGroupIdx = comboSpaceGroups->currentIndex(); + if(iSpaceGroupIdx != 0) + pSpaceGroup = (SpaceGroup*)comboSpaceGroups->itemData(iSpaceGroupIdx).value(); + return pSpaceGroup; +} + +void DispDlg::SpaceGroupChanged() +{ + m_crystalsys = CrystalSystem::CRYS_NOT_SET; + std::string strCryTy = ""; + + const SpaceGroup* pSpaceGroup = GetCurSpaceGroup(); + if(pSpaceGroup) + { + m_crystalsys = pSpaceGroup->GetCrystalSystem(); + strCryTy = pSpaceGroup->GetCrystalSystemName(); + } + editCrystalSystem->setText(strCryTy.c_str()); + + CheckCrystalType(); + Calc(); +} + +void DispDlg::RepopulateSpaceGroups() +{ + if(!m_pmapSpaceGroups) + return; + + for(int iCnt=comboSpaceGroups->count()-1; iCnt>0; --iCnt) + comboSpaceGroups->removeItem(iCnt); + + std::string strFilter = editSpaceGroupsFilter->text().toStdString(); + + for(const SpaceGroups::t_mapSpaceGroups::value_type& pair : *m_pmapSpaceGroups) + { + const std::string& strName = pair.second.GetName(); + + typedef const boost::iterator_range t_striterrange; + if(strFilter!="" && + !boost::ifind_first(t_striterrange(strName.begin(), strName.end()), + t_striterrange(strFilter.begin(), strFilter.end()))) + continue; + + comboSpaceGroups->insertItem(comboSpaceGroups->count(), + strName.c_str(), QVariant::fromValue((void*)&pair.second)); + } +} + +void DispDlg::CheckCrystalType() +{ + set_crystal_system_edits(m_crystalsys, editA, editB, editC, + editAlpha, editBeta, editGamma); +} + +void DispDlg::Save() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + m_pSettings->value("disp/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getSaveFileName(this, + "Save Dispersion Configuration", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + + if(qstrFile == "") + return; + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + std::map mapConf; + Save(mapConf, strXmlRoot); + + tl::Prop xml; + xml.Add(mapConf); + + bool bOk = xml.Save(strFile.c_str(), tl::PropType::XML); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not save dispersion file."); + + if(bOk && m_pSettings) + m_pSettings->setValue("disp/last_dir", QString(strDir.c_str())); +} + +void DispDlg::dragEnterEvent(QDragEnterEvent *pEvt) +{ + if(pEvt) pEvt->accept(); +} + +void DispDlg::dropEvent(QDropEvent *pEvt) +{ + if(!pEvt) return; + const QMimeData* pMime = pEvt->mimeData(); + if(!pMime) return; + + std::string strFiles = pMime->text().toStdString(); + std::vector vecFiles; + tl::get_tokens(strFiles, "\n", vecFiles); + if(vecFiles.size() > 1) + tl::log_warn("More than one file dropped, using first one."); + + if(vecFiles.size() >= 1) + { + std::string& strFile = vecFiles[0]; + tl::trim(strFile); + + const std::string strHead = "file://"; + if(algo::starts_with(strFile, strHead)) + algo::replace_head(strFile, strHead.length(), ""); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load dispersion file."); + return; + } + + const std::string strXmlRoot("taz/"); + Load(xml, strXmlRoot); + } +} + +void DispDlg::Load() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + strDirLast = m_pSettings->value("disp/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getOpenFileName(this, + "Open Dispersion Configuration", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + if(qstrFile == "") + return; + + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load dispersion file."); + return; + } + + Load(xml, strXmlRoot); + if(m_pSettings) + m_pSettings->setValue("disp/last_dir", QString(strDir.c_str())); +} + +void DispDlg::Save(std::map& mapConf, const std::string& strXmlRoot) +{ + mapConf[strXmlRoot + "sample/a"] = editA->text().toStdString(); + mapConf[strXmlRoot + "sample/b"] = editB->text().toStdString(); + mapConf[strXmlRoot + "sample/c"] = editC->text().toStdString(); + + mapConf[strXmlRoot + "sample/alpha"] = editAlpha->text().toStdString(); + mapConf[strXmlRoot + "sample/beta"] = editBeta->text().toStdString(); + mapConf[strXmlRoot + "sample/gamma"] = editGamma->text().toStdString(); + + mapConf[strXmlRoot + "disp/neighbours"] = tl::var_to_str(spinNN->value(), g_iPrec); + mapConf[strXmlRoot + "disp/supercell"] = tl::var_to_str(spinSC->value(), g_iPrec); + mapConf[strXmlRoot + "disp/centre_idx"] = tl::var_to_str(spinCentreIdx->value(), g_iPrec); + mapConf[strXmlRoot + "disp/S"] = editS->text().toStdString(); + mapConf[strXmlRoot + "disp/eps_shell"] = editEpsShell->text().toStdString(); + + mapConf[strXmlRoot + "sample/spacegroup"] = comboSpaceGroups->currentText().toStdString(); + + // atom positions + mapConf[strXmlRoot + "sample/atoms/num"] = tl::var_to_str(m_vecAtoms.size()); + for(std::size_t iAtom=0; iAtom& atom = m_vecAtoms[iAtom]; + + std::string strAtomNr = tl::var_to_str(iAtom); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/name"] = + atom.strAtomName; + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/x"] = + tl::var_to_str(atom.vecPos[0], g_iPrec); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/y"] = + tl::var_to_str(atom.vecPos[1], g_iPrec); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/z"] = + tl::var_to_str(atom.vecPos[2], g_iPrec); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/J"] = + tl::var_to_str(atom.J, g_iPrec); + } +} + +void DispDlg::Load(tl::Prop& xml, const std::string& strXmlRoot) +{ + m_bDontCalc = 1; + bool bOk=0; + + editA->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/a").c_str(), 5., &bOk), g_iPrec).c_str()); + editB->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/b").c_str(), 5., &bOk), g_iPrec).c_str()); + editC->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/c").c_str(), 5., &bOk), g_iPrec).c_str()); + + editAlpha->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/alpha").c_str(), 90., &bOk), g_iPrec).c_str()); + editBeta->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/beta").c_str(), 90., &bOk), g_iPrec).c_str()); + editGamma->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/gamma").c_str(), 90., &bOk), g_iPrec).c_str()); + + spinNN->setValue(xml.Query((strXmlRoot + "disp/neighbours").c_str(), 2, &bOk)); + spinSC->setValue(xml.Query((strXmlRoot + "disp/supercell").c_str(), 2, &bOk)); + spinCentreIdx->setValue(xml.Query((strXmlRoot + "disp/centre_idx").c_str(), 0, &bOk)); + + editS->setText(tl::var_to_str(xml.Query((strXmlRoot + "disp/S").c_str(), 0.5, &bOk), g_iPrec).c_str()); + editEpsShell->setText(tl::var_to_str(xml.Query((strXmlRoot + "disp/eps_shell").c_str(), 0.01, &bOk), g_iPrec).c_str()); + + std::string strSpaceGroup = xml.Query((strXmlRoot + "sample/spacegroup").c_str(), "", &bOk); + tl::trim(strSpaceGroup); + if(bOk) + { + editSpaceGroupsFilter->clear(); + int iSGIdx = comboSpaceGroups->findText(strSpaceGroup.c_str()); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); + } + + + // atom positions + m_vecAtoms.clear(); + unsigned int iNumAtoms = xml.Query((strXmlRoot + "sample/atoms/num").c_str(), 0, &bOk); + if(bOk) + { + m_vecAtoms.reserve(iNumAtoms); + + for(std::size_t iAtom=0; iAtom atom; + atom.vecPos.resize(3,0); + + std::string strNr = tl::var_to_str(iAtom); + atom.strAtomName = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/name").c_str(), ""); + atom.vecPos[0] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/x").c_str(), 0.); + atom.vecPos[1] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/y").c_str(), 0.); + atom.vecPos[2] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/z").c_str(), 0.); + atom.J = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/J").c_str(), 0.); + + m_vecAtoms.push_back(atom); + } + + spinCentreIdx->setMaximum(int(m_vecAtoms.size())-1); + } + + m_bDontCalc = 0; + Calc(); +} + +void DispDlg::ApplyAtoms(const std::vector>& vecAtoms) +{ + m_vecAtoms = vecAtoms; + spinCentreIdx->setMaximum(int(m_vecAtoms.size())-1); + + Calc(); +} + +void DispDlg::ShowAtomDlg() +{ + if(!m_pAtomsDlg) + { + m_pAtomsDlg = new AtomsDlg(this, m_pSettings, true); + m_pAtomsDlg->setWindowTitle(m_pAtomsDlg->windowTitle() + QString(" (Dispersion)")); + + QObject::connect(m_pAtomsDlg, SIGNAL(ApplyAtoms(const std::vector>&)), + this, SLOT(ApplyAtoms(const std::vector>&))); + } + + m_pAtomsDlg->SetAtoms(m_vecAtoms); + m_pAtomsDlg->show(); + m_pAtomsDlg->activateWindow(); +} + +void DispDlg::cursorMoved(const QPointF& pt) +{ + const t_real dPos[] = { pt.x(), pt.y() }; + + //const std::wstring strAA = tl::get_spec_char_utf16("AA") + + // tl::get_spec_char_utf16("sup-") + tl::get_spec_char_utf16("sup1"); + + std::wostringstream ostr; + ostr.precision(g_iPrecGfx); + ostr << L"q = " << dPos[0] << L" " << L"rlu" /*strAA*/ << L", "; + ostr << L"E = " << dPos[1] << L" meV"; + + labStatus->setText(QString::fromWCharArray(ostr.str().c_str())); +} + +void DispDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("disp/geo", saveGeometry()); + + QDialog::accept(); +} + +void DispDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "DispDlg.moc" diff --git a/dialogs/DispDlg.h b/dialogs/DispDlg.h new file mode 100644 index 0000000..12e2691 --- /dev/null +++ b/dialogs/DispDlg.h @@ -0,0 +1,78 @@ +/** + * Dispersion Dialog + * @author Tobias Weber + * @date may-2016 + * @license GPLv2 + */ + +#ifndef __DISP_DLG_H__ +#define __DISP_DLG_H__ + +#include "ui/ui_disp.h" + +#include "libs/spacegroups/spacegroup.h" +#include "libs/qthelper.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "tlibs/file/prop.h" +#include "AtomsDlg.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + + +class DispDlg : public QDialog, Ui::DispDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + bool m_bDontCalc = 1; + + CrystalSystem m_crystalsys = CRYS_NOT_SET; + const SpaceGroups::t_mapSpaceGroups* m_pmapSpaceGroups; + + AtomsDlg *m_pAtomsDlg = nullptr; + std::vector> m_vecAtoms; + + std::vector m_vecFerroQ, m_vecFerroE; + std::unique_ptr m_plotwrapFerro; + + public: + DispDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~DispDlg(); + + protected slots: + void Calc(); + + void CheckCrystalType(); + void SpaceGroupChanged(); + void RepopulateSpaceGroups(); + + void Save(); + void Load(); + + void ShowAtomDlg(); + void ApplyAtoms(const std::vector>&); + + void cursorMoved(const QPointF& pt); + + virtual void dragEnterEvent(QDragEnterEvent *pEvt) override; + virtual void dropEvent(QDropEvent *pEvt) override; + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + + const SpaceGroup* GetCurSpaceGroup() const; + + void Save(std::map& mapConf, const std::string& strXmlRoot); + void Load(tl::Prop& xml, const std::string& strXmlRoot); +}; + +#endif diff --git a/dialogs/DynPlaneDlg.cpp b/dialogs/DynPlaneDlg.cpp new file mode 100644 index 0000000..4fdd6f6 --- /dev/null +++ b/dialogs/DynPlaneDlg.cpp @@ -0,0 +1,153 @@ +/* + * Dynamic Plane Dialog + * @author tweber + * @date 2013, jan-2015 + * @license GPLv2 + */ + +#include "DynPlaneDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/math/neutrons.h" +#include + +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_angle_si rads = tl::get_one_radian(); + + +DynPlaneDlg::DynPlaneDlg(QWidget* pParent, QSettings *pSettings) + : QDialog(pParent), m_pSettings(pSettings) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + + m_plotwrap.reset(new QwtPlotWrapper(plot)); + m_plotwrap->GetCurve(0)->setTitle("Kinematic Plane"); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Q (1/A)"); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::yLeft, "E (meV)"); + if(m_plotwrap->HasTrackerSignal()) + connect(m_plotwrap->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + + QObject::connect(comboFixedE, SIGNAL(currentIndexChanged(int)), this, SLOT(FixedKiKfToggled())); + + std::vector vecSpinBoxes = {spinEiEf, spinMinQ, spinMaxQ, spinAngle}; + for(QDoubleSpinBox* pSpin : vecSpinBoxes) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(Calc())); + QObject::connect(btnSync, SIGNAL(toggled(bool)), this, SLOT(Calc())); + + Calc(); + + + if(m_pSettings && m_pSettings->contains("dyn_plane/geo")) + restoreGeometry(m_pSettings->value("dyn_plane/geo").toByteArray()); +} + +DynPlaneDlg::~DynPlaneDlg() +{} + +void DynPlaneDlg::cursorMoved(const QPointF& pt) +{ + std::string strX = tl::var_to_str(pt.x(), g_iPrecGfx); + std::string strY = tl::var_to_str(pt.y(), g_iPrecGfx); + + std::ostringstream ostr; + ostr << "(" << strX << ", " << strY << ")"; + + this->labelStatus->setText(ostr.str().c_str()); +} + +void DynPlaneDlg::Calc() +{ + const unsigned int NUM_POINTS = 512; + + const t_real dMinQ = spinMinQ->value(); + const t_real dMaxQ = spinMaxQ->value(); + const t_real dAngle = tl::d2r(spinAngle->value()); + const bool bFixedKi = (comboFixedE->currentIndex()==0); + + if(btnSync->isChecked()) + spinEiEf->setValue(bFixedKi ? m_dEi : m_dEf); + + tl::t_energy_si EiEf = t_real(spinEiEf->value()) * meV; + + + //m_pPlanePlot->clear(); + std::vector vecQ[2], vecE[2]; + vecQ[0].reserve(NUM_POINTS); vecE[0].reserve(NUM_POINTS); + vecQ[1].reserve(NUM_POINTS); vecE[1].reserve(NUM_POINTS); + + tl::t_angle_si twotheta = dAngle * rads; + + for(unsigned int iPt=0; iPt Q = (dMinQ + (dMaxQ - dMinQ)/t_real(NUM_POINTS)*t_real(iPt)) / angs; + tl::t_energy_si dE = tl::kinematic_plane(bFixedKi, iSign, EiEf, Q, twotheta); + + t_real _dQ = Q * angs; + t_real _dE = dE / meV; + + if(!std::isnan(_dQ) && !std::isnan(_dE) && !std::isinf(_dQ) && !std::isinf(_dE)) + { + vecQ[iSign].push_back(Q * angs); + vecE[iSign].push_back(dE / meV); + } + } + } + + m_vecQ.clear(); + m_vecE.clear(); + + m_vecQ.insert(m_vecQ.end(), vecQ[0].rbegin(), vecQ[0].rend()); + m_vecE.insert(m_vecE.end(), vecE[0].rbegin(), vecE[0].rend()); + + m_vecQ.insert(m_vecQ.end(), vecQ[1].begin(), vecQ[1].end()); + m_vecE.insert(m_vecE.end(), vecE[1].begin(), vecE[1].end()); + + set_qwt_data()(*m_plotwrap, m_vecQ, m_vecE); +} + +void DynPlaneDlg::RecipParamsChanged(const RecipParams& params) +{ + m_d2Theta = params.d2Theta; + m_dEi = tl::k2E(params.dki/angs)/meV; + m_dEf = tl::k2E(params.dkf/angs)/meV; + + Calc(); +} + +void DynPlaneDlg::FixedKiKfToggled() +{ + if(comboFixedE->currentIndex() == 0) + labelFixedKiKf->setText("E_i (meV):"); + else + labelFixedKiKf->setText("E_f (meV):"); + + Calc(); +} + + +void DynPlaneDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + +void DynPlaneDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("dyn_plane/geo", saveGeometry()); + + QDialog::accept(); +} + + +#include "DynPlaneDlg.moc" diff --git a/dialogs/DynPlaneDlg.h b/dialogs/DynPlaneDlg.h new file mode 100644 index 0000000..6d8297d --- /dev/null +++ b/dialogs/DynPlaneDlg.h @@ -0,0 +1,49 @@ +/* + * Dynamic Plane Dialog + * @author tweber + * @date 2013, jan-2015 + * @license GPLv2 + */ + +#ifndef __DYN_PLANE_DLG_H__ +#define __DYN_PLANE_DLG_H__ + +#include +#include +#include +#include +#include "ui/ui_dyn_plane.h" +#include "RecipParamDlg.h" +#include "libs/qthelper.h" +#include "libs/globals.h" + + +class DynPlaneDlg : public QDialog, Ui::DynPlaneDlg +{ Q_OBJECT +protected: + QSettings *m_pSettings = nullptr; + std::vector m_vecQ, m_vecE; + std::unique_ptr m_plotwrap; + + t_real_glob m_d2Theta = 0.; + t_real_glob m_dEi = 5., m_dEf = 5.; + +protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + +protected slots: + void cursorMoved(const QPointF& pt); + void Calc(); + void FixedKiKfToggled(); + +public slots: + void RecipParamsChanged(const RecipParams&); + + +public: + DynPlaneDlg(QWidget* pParent = nullptr, QSettings *pSettings = nullptr); + virtual ~DynPlaneDlg(); +}; + +#endif diff --git a/dialogs/EllipseDlg.cpp b/dialogs/EllipseDlg.cpp new file mode 100644 index 0000000..d3b5749 --- /dev/null +++ b/dialogs/EllipseDlg.cpp @@ -0,0 +1,349 @@ +/** + * Ellipse Dialog + * @author Tobias Weber + * @date 2013 - 2016 + * @license GPLv2 + */ + +#include "EllipseDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/helper/flags.h" + +#include + + +EllipseDlg::EllipseDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setupUi(this); + setWindowTitle(m_pcTitle); + + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + + m_bCenterOn0 = m_pSettings->value("reso/center_around_origin", 1).toInt() != 0; + } + + m_vecplotwrap.reserve(4); + m_elliProj.resize(4); + m_elliSlice.resize(4); + m_vecXCurvePoints.resize(8); + m_vecYCurvePoints.resize(8); + + QwtPlot* pPlots[] = {plot1, plot2, plot3, plot4}; + for(unsigned int i=0; i<4; ++i) + { + m_vecplotwrap.push_back(std::unique_ptr(new QwtPlotWrapper(pPlots[i], 2))); + m_vecplotwrap[i]->GetPlot()->setMinimumSize(200,200); + + m_vecplotwrap[i]->GetCurve(0)->setTitle("Projected Ellipse"); + m_vecplotwrap[i]->GetCurve(1)->setTitle("Sliced Ellipse"); + + QPen penProj, penSlice; + penProj.setColor(QColor(0, 0x99,0)); + penSlice.setColor(QColor(0,0,0x99)); + penProj.setWidth(2); + penSlice.setWidth(2); + + m_vecplotwrap[i]->GetCurve(0)->setPen(penProj); + m_vecplotwrap[i]->GetCurve(1)->setPen(penSlice); + + if(m_vecplotwrap[i]->HasTrackerSignal()) + { +#if QT_VER >= 5 + connect(m_vecplotwrap[i]->GetPicker(), &QwtPlotPicker::moved, + this, &EllipseDlg::cursorMoved); +#else + connect(m_vecplotwrap[i]->GetPicker(), SIGNAL(moved(const QPointF&)), + this, SLOT(cursorMoved(const QPointF&))); +#endif + } + } + +#if QT_VER >= 5 + QObject::connect(comboCoord, static_cast(&QComboBox::currentIndexChanged), + this, &EllipseDlg::Calc); + QObject::connect(checkCenter, static_cast(&QCheckBox::toggled), + this, &EllipseDlg::SetCenterOn0); +#else + QObject::connect(comboCoord, SIGNAL(currentIndexChanged(int)), this, SLOT(Calc())); + QObject::connect(checkCenter, SIGNAL(toggled(bool)), this, SLOT(SetCenterOn0(bool))); +#endif + + if(m_pSettings && m_pSettings->contains("reso/ellipse_geo")) + restoreGeometry(m_pSettings->value("reso/ellipse_geo").toByteArray()); + m_bReady = 1; +} + +EllipseDlg::~EllipseDlg() +{ + m_vecplotwrap.clear(); +} + +void EllipseDlg::SetTitle(const char* pcTitle) +{ + QString strTitle = m_pcTitle; + strTitle += " ("; + strTitle += pcTitle; + strTitle += ")"; + this->setWindowTitle(strTitle); +} + + +void EllipseDlg::cursorMoved(const QPointF& pt) +{ + std::string strX = tl::var_to_str(pt.x(), g_iPrecGfx); + std::string strY = tl::var_to_str(pt.y(), g_iPrecGfx); + + std::ostringstream ostr; + ostr << "(" << strX << ", " << strY << ")"; + + this->labelStatus->setText(ostr.str().c_str()); +} + + +void EllipseDlg::Calc() +{ + if(!m_bReady) return; + const EllipseCoordSys coord = static_cast(comboCoord->currentIndex()); + + const ublas::matrix *pReso = nullptr; + const ublas::vector *pReso_v = nullptr; + const ublas::vector *pQavg = nullptr; + + switch(coord) + { + case EllipseCoordSys::Q_AVG: // Q|| Qperp system in 1/A + pReso = &m_reso; + pQavg = &m_Q_avg; + pReso_v = &m_reso_v; + break; + case EllipseCoordSys::RLU: // rlu system + pReso = &m_resoHKL; + pQavg = &m_Q_avgHKL; + pReso_v = &m_reso_vHKL; + break; + case EllipseCoordSys::RLU_ORIENT: // rlu system + pReso = &m_resoOrient; + pQavg = &m_Q_avgOrient; + pReso_v = &m_reso_vOrient; + break; + default: + tl::log_err("Unknown coordinate system selected."); return; + } + + + const ublas::matrix& reso = *pReso; + const ublas::vector& reso_v = *pReso_v; + const t_real_reso& reso_s = m_reso_s; + const ublas::vector& _Q_avg = *pQavg; + + try + { + int iParams[2][4][5] = + { + { // projected + {0, 3, 1, 2, -1}, + {1, 3, 0, 2, -1}, + {2, 3, 0, 1, -1}, + {0, 1, 3, 2, -1} + }, + { // sliced + {0, 3, -1, 2, 1}, + {1, 3, -1, 2, 0}, + {2, 3, -1, 1, 0}, + {0, 1, -1, 2, 3} + } + }; + + static const std::string strDeg = tl::get_spec_char_utf8("deg"); + + ublas::vector Q_avg = _Q_avg; + if(m_bCenterOn0) + Q_avg = ublas::zero_vector(Q_avg.size()); + + + std::vector>> tasks_ell_proj, tasks_ell_slice; + + for(unsigned int iEll=0; iEll<4; ++iEll) + { + if(m_pSettings) + { + std::ostringstream ostrCfg; + ostrCfg << "reso/ellipse_2d_" << iEll; + std::string strProjPath = ostrCfg.str() + "_proj"; + std::string strSlicePath = ostrCfg.str() + "_slice"; + + std::string strProj = m_pSettings->value(strProjPath.c_str(), "").toString().toStdString(); + std::string strSlice = m_pSettings->value(strSlicePath.c_str(), "").toString().toStdString(); + + const std::string* strEllis[] = {&strProj, &strSlice}; + + for(unsigned int iWhichEll=0; iWhichEll<2; ++iWhichEll) + { + if(*strEllis[iWhichEll] != "") + { + std::vector vecIdx; + tl::get_tokens(*strEllis[iWhichEll], std::string(","), vecIdx); + + if(vecIdx.size() == 5) + { + for(unsigned int iParam=0; iParam<5; ++iParam) + iParams[iWhichEll][iEll][iParam] = vecIdx[iParam]; + } + else + { + tl::log_err("Error in res.conf: Wrong size of parameters for ", + strProj, "."); + } + } + } + } + + const int *iP = iParams[0][iEll]; + const int *iS = iParams[1][iEll]; + + std::future> ell_proj = + std::async(std::launch::deferred|std::launch::async, + [=, &reso, &Q_avg]() + { return ::calc_res_ellipse( + reso, reso_v, reso_s, Q_avg, iP[0], iP[1], iP[2], iP[3], iP[4]); }); + std::future> ell_slice = + std::async(std::launch::deferred|std::launch::async, + [=, &reso, &Q_avg]() + { return ::calc_res_ellipse( + reso, reso_v, reso_s, Q_avg, iS[0], iS[1], iS[2], iS[3], iS[4]); }); + + tasks_ell_proj.push_back(std::move(ell_proj)); + tasks_ell_slice.push_back(std::move(ell_slice)); + } + + for(unsigned int iEll=0; iEll<4; ++iEll) + { + m_elliProj[iEll] = tasks_ell_proj[iEll].get(); + m_elliSlice[iEll] = tasks_ell_slice[iEll].get(); + + /*m_elliProj[iEll] = ::calc_res_ellipse(res.reso, Q_avg, iParams[0][iEll][0], iParams[0][iEll][1], + iParams[0][iEll][2], iParams[0][iEll][3], iParams[0][iEll][4]); + m_elliSlice[iEll] = ::calc_res_ellipse(res.reso, Q_avg, iParams[1][iEll][0], iParams[1][iEll][1], + iParams[1][iEll][2], iParams[1][iEll][3], iParams[1][iEll][4]);*/ + + std::vector& vecXProj = m_vecXCurvePoints[iEll*2+0]; + std::vector& vecYProj = m_vecYCurvePoints[iEll*2+0]; + std::vector& vecXSlice = m_vecXCurvePoints[iEll*2+1]; + std::vector& vecYSlice = m_vecYCurvePoints[iEll*2+1]; + + t_real_reso dBBProj[4], dBBSlice[4]; + m_elliProj[iEll].GetCurvePoints(vecXProj, vecYProj, 512, dBBProj); + m_elliSlice[iEll].GetCurvePoints(vecXSlice, vecYSlice, 512, dBBSlice); + + set_qwt_data()(*m_vecplotwrap[iEll], vecXProj, vecYProj, 0, false); + set_qwt_data()(*m_vecplotwrap[iEll], vecXSlice, vecYSlice, 1, false); + //m_vecplotwrap[iEll]->SetData(vecXProj, vecYProj, 0, false); + //m_vecplotwrap[iEll]->SetData(vecXSlice, vecYSlice, 1, false); + + + std::ostringstream ostrSlope; + ostrSlope.precision(4); + ostrSlope << "Projected ellipse (green):\n"; + ostrSlope << "\tSlope: " << m_elliProj[iEll].slope << "\n"; + ostrSlope << "\tAngle: " << tl::r2d(m_elliProj[iEll].phi) << strDeg << "\n"; + ostrSlope << "\tArea " << m_elliProj[iEll].area << "\n"; + ostrSlope << "Sliced ellipse (blue):\n"; + ostrSlope << "\tSlope: " << m_elliSlice[iEll].slope << "\n"; + ostrSlope << "\tAngle: " << tl::r2d(m_elliSlice[iEll].phi) << strDeg << "\n"; + ostrSlope << "\tArea " << m_elliSlice[iEll].area; + //m_vecplotwrap[iEll]->GetPlot()->setTitle(ostrSlope.str().c_str()); + //std::cout << "Ellipse " << iEll << ": " << ostrSlope.str() << std::endl; + m_vecplotwrap[iEll]->GetPlot()->setToolTip(QString::fromUtf8(ostrSlope.str().c_str())); + + //const std::string& strLabX = m_elliProj[iEll].x_lab; + //const std::string& strLabY = m_elliProj[iEll].y_lab; + const std::string& strLabX = ellipse_labels(iParams[0][iEll][0], coord); + const std::string& strLabY = ellipse_labels(iParams[0][iEll][1], coord); + m_vecplotwrap[iEll]->GetPlot()->setAxisTitle(QwtPlot::xBottom, strLabX.c_str()); + m_vecplotwrap[iEll]->GetPlot()->setAxisTitle(QwtPlot::yLeft, strLabY.c_str()); + + m_vecplotwrap[iEll]->GetPlot()->replot(); + + QRectF rect; + rect.setLeft(std::min(dBBProj[0], dBBSlice[0])); + rect.setRight(std::max(dBBProj[1], dBBSlice[1])); + rect.setTop(std::max(dBBProj[2], dBBSlice[2])); + rect.setBottom(std::min(dBBProj[3], dBBSlice[3])); + if(m_vecplotwrap[iEll]->GetZoomer()) + m_vecplotwrap[iEll]->GetZoomer()->setZoomBase(rect); + + switch(m_algo) + { + case ResoAlgo::CN: SetTitle("Cooper-Nathans Algorithm (TAS)"); break; + case ResoAlgo::POP: SetTitle("Popovici Algorithm (TAS)"); break; + case ResoAlgo::ECK: SetTitle("Eckold-Sobolev Algorithm (TAS)"); break; + case ResoAlgo::VIOL: SetTitle("Violini Algorithm (TOF)"); break; + case ResoAlgo::SIMPLE: SetTitle("Simple Algorithm"); break; + default: SetTitle("Unknown Resolution Algorithm"); break; + } + + /*if(iEll == 0) + tl::log_err("reso v = ", reso_v, + ", proj offs: ", m_elliProj[iEll].x_offs, " ", m_elliProj[iEll].y_offs, + ", slice offs: ", m_elliSlice[iEll].x_offs, " ", m_elliSlice[iEll].y_offs);*/ + } + } + catch(const std::exception& ex) + { + tl::log_err("Cannot calculate ellipses."); + SetTitle("Error"); + } +} + + +void EllipseDlg::SetCenterOn0(bool bCenter) +{ + m_bCenterOn0 = bCenter; + Calc(); +} + + +void EllipseDlg::SetParams(const EllipseDlgParams& params) +{ + static const ublas::matrix mat0 = ublas::zero_matrix(4,4); + static const ublas::vector vec0 = ublas::zero_vector(4); + + if(params.reso) m_reso = *params.reso; else m_reso = mat0; + if(params.reso_v) m_reso_v = *params.reso_v; else m_reso_v = vec0; + m_reso_s = params.reso_s; + if(params.Q_avg) m_Q_avg = *params.Q_avg; else m_Q_avg = vec0; + + if(params.resoHKL) m_resoHKL = *params.resoHKL; else m_resoHKL = mat0; + if(params.reso_vHKL) m_reso_vHKL = *params.reso_vHKL; else m_reso_vHKL = vec0; + if(params.Q_avgHKL) m_Q_avgHKL = *params.Q_avgHKL; else m_Q_avgHKL = vec0; + + if(params.resoOrient) m_resoOrient = *params.resoOrient; else m_resoOrient = mat0; + if(params.reso_vOrient) m_reso_vOrient = *params.reso_vOrient; else m_reso_vOrient = vec0; + if(params.Q_avgOrient) m_Q_avgOrient = *params.Q_avgOrient; else m_Q_avgOrient = vec0; + + m_algo = params.algo; + + Calc(); +} + +void EllipseDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("reso/ellipse_geo", saveGeometry()); + + QDialog::accept(); +} + +void EllipseDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "EllipseDlg.moc" diff --git a/dialogs/EllipseDlg.h b/dialogs/EllipseDlg.h new file mode 100644 index 0000000..af5babe --- /dev/null +++ b/dialogs/EllipseDlg.h @@ -0,0 +1,93 @@ +/* + * Ellipse Dialog + * @author Tobias Weber + * @date 2013 - 2016 + * @license GPLv2 + */ + +#ifndef __RESO_ELLI_DLG__ +#define __RESO_ELLI_DLG__ + +#include +#include +#if QT_VER>=5 + #include +#endif + +#include +#include + +#include "tlibs/math/linalg.h" +#include "tools/res/ellipse.h" +#include "tools/res/pop.h" +#include "ui/ui_ellipses.h" +#include "libs/qthelper.h" + + +struct EllipseDlgParams +{ + const ublas::matrix* reso = nullptr; + const ublas::vector* reso_v = nullptr; + t_real_reso reso_s = 0; + const ublas::vector* Q_avg = nullptr; + + const ublas::matrix* resoHKL = nullptr; + const ublas::vector* reso_vHKL = nullptr; + const ublas::vector* Q_avgHKL = nullptr; + + const ublas::matrix* resoOrient = nullptr; + const ublas::vector* reso_vOrient = nullptr; + const ublas::vector* Q_avgOrient = nullptr; + + ResoAlgo algo = ResoAlgo::UNKNOWN; +}; + + +class EllipseDlg : public QDialog, Ui::EllipseDlg +{ Q_OBJECT + private: + const char* m_pcTitle = "Resolution Ellipses"; + + protected: + bool m_bReady = 0; + bool m_bCenterOn0 = 1; + std::vector> m_vecplotwrap; + + std::vector> m_elliProj; + std::vector> m_elliSlice; + + std::vector > m_vecXCurvePoints; + std::vector > m_vecYCurvePoints; + + QSettings *m_pSettings = 0; + + protected: + ublas::matrix m_reso, m_resoHKL, m_resoOrient; + ublas::vector m_reso_v = ublas::zero_vector(4), + m_reso_vHKL = ublas::zero_vector(4), + m_reso_vOrient = ublas::zero_vector(4); + t_real_reso m_reso_s = 0; + ublas::vector m_Q_avg, m_Q_avgHKL, m_Q_avgOrient; + ResoAlgo m_algo = ResoAlgo::UNKNOWN; + + public: + EllipseDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~EllipseDlg(); + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + + protected slots: + void cursorMoved(const QPointF& pt); + + public slots: + void SetParams(const EllipseDlgParams& params); + void Calc(); + void SetCenterOn0(bool bCenter); + + public: + void SetTitle(const char* pcTitle); +}; + +#endif diff --git a/dialogs/EllipseDlg3D.cpp b/dialogs/EllipseDlg3D.cpp new file mode 100644 index 0000000..59ed6ee --- /dev/null +++ b/dialogs/EllipseDlg3D.cpp @@ -0,0 +1,242 @@ +/** + * 3D Ellipsoid Dialog + * @author Tobias Weber + * @date may-2013, 29-apr-2014 + * @license GPLv2 + */ + +#include "EllipseDlg3D.h" +#include +//#include + + +EllipseDlg3D::EllipseDlg3D(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setWindowFlags(Qt::Tool); + setWindowTitle("Resolution Ellipsoids"); + setSizeGripEnabled(1); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + PlotGl* pPlotLeft = new PlotGl(this, m_pSettings); + pPlotLeft->SetPrec(g_iPrecGfx); + pPlotLeft->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_pPlots.push_back(pPlotLeft); + + PlotGl* pPlotRight = new PlotGl(this, m_pSettings); + pPlotRight->SetPrec(g_iPrecGfx); + pPlotRight->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_pPlots.push_back(pPlotRight); + + m_pComboCoord = new QComboBox(this); + m_pComboCoord->insertItem(0, "(Q perpendicular, Q parallel, Q up) System (1/A)"); + m_pComboCoord->insertItem(1, "Crystal (hkl) System (rlu)"); + m_pComboCoord->insertItem(2, "Scattering Plane System (rlu)"); + + QGridLayout *pgridLayout = new QGridLayout(this); + pgridLayout->setContentsMargins(4, 4, 4, 4); + pgridLayout->addWidget(pPlotLeft, 0, 0, 1, 1); + pgridLayout->addWidget(pPlotRight, 0, 1, 1, 1); + pgridLayout->addWidget(m_pComboCoord, 1, 0, 1, 1); + + /*QSplitter *pSplitter = new QSplitter(this); + pSplitter->setOrientation(Qt::Horizontal); + pSplitter->addWidget(pPlotLeft); + pSplitter->addWidget(pPlotRight); + pgridLayout->addWidget(pSplitter, 0, 0, 1, 1);*/ + + m_elliProj.resize(2); + m_elliSlice.resize(2); + + resize(640,480); + +#if QT_VER >= 5 + QObject::connect(m_pComboCoord, static_cast + (&QComboBox::currentIndexChanged), this, &EllipseDlg3D::Calc); +#else + QObject::connect(m_pComboCoord, SIGNAL(currentIndexChanged(int)), this, SLOT(Calc())); +#endif + + if(m_pSettings && m_pSettings->contains("reso/ellipsoid3d_geo")) + restoreGeometry(m_pSettings->value("reso/ellipsoid3d_geo").toByteArray()); + + for(unsigned int i=0; iSetEnabled(1); +} + +EllipseDlg3D::~EllipseDlg3D() +{ + for(PlotGl* pPlot : m_pPlots) + delete pPlot; + m_pPlots.clear(); +} + +void EllipseDlg3D::hideEvent(QHideEvent *event) +{ + for(unsigned int i=0; iSetEnabled(0); + + if(m_pSettings) + m_pSettings->setValue("reso/ellipsoid3d_geo", saveGeometry()); +} + +void EllipseDlg3D::showEvent(QShowEvent *event) +{ + QDialog::showEvent(event); + + for(unsigned int i=0; iSetEnabled(1); +} + + +ublas::vector +EllipseDlg3D::ProjRotatedVec(const ublas::matrix& rot, + const ublas::vector& vec) +{ + ublas::vector vecCoord(3); + + ublas::vector x = ublas::zero_vector(3); + x[0] = 1.; + ublas::vector y = ublas::zero_vector(3); + y[1] = 1.; + ublas::vector z = ublas::zero_vector(3); + z[2] = 1.; + + const ublas::vector vecrot_x = ublas::prod(rot, x*vec[0]); + const ublas::vector vecrot_y = ublas::prod(rot, y*vec[1]); + const ublas::vector vecrot_z = ublas::prod(rot, z*vec[2]); + + vecCoord[0] = std::fabs(vecrot_x[0]) + std::fabs(vecrot_y[0]) + std::fabs(vecrot_z[0]); + vecCoord[1] = std::fabs(vecrot_x[1]) + std::fabs(vecrot_y[1]) + std::fabs(vecrot_z[1]); + vecCoord[2] = std::fabs(vecrot_x[2]) + std::fabs(vecrot_y[2]) + std::fabs(vecrot_z[2]); + + return vecCoord; +} + + +void EllipseDlg3D::Calc() +{ + const EllipseCoordSys coord = static_cast(m_pComboCoord->currentIndex()); + + const ublas::matrix *pReso = nullptr; + const ublas::vector *pReso_v = nullptr; + const ublas::vector *pQavg = nullptr; + + switch(coord) + { + case EllipseCoordSys::Q_AVG: // Q|| Qperp system in 1/A + pReso = &m_reso; + pQavg = &m_Q_avg; + pReso_v = &m_reso_v; + break; + case EllipseCoordSys::RLU: // rlu system + pReso = &m_resoHKL; + pQavg = &m_Q_avgHKL; + pReso_v = &m_reso_vHKL; + break; + case EllipseCoordSys::RLU_ORIENT: // rlu system + pReso = &m_resoOrient; + pQavg = &m_Q_avgOrient; + pReso_v = &m_reso_vOrient; + break; + default: + tl::log_err("Unknown coordinate system selected."); return; + } + + + const ublas::matrix& reso = *pReso; + const ublas::vector& reso_v = *pReso_v; + const t_real_reso& reso_s = m_reso_s; + const ublas::vector& _Q_avg = *pQavg; + + + const int iX[] = {0, 0}; + const int iY[] = {1, 1}; + const int iZ[] = {3, 2}; + const int iIntOrRem[] = {2, 3}; + + //Xml xmlparams; + //bool bXMLLoaded = xmlparams.Load("res/res.conf"); + bool bCenterOn0 = 1; //xmlparams.Query("/res/center_around_origin", 0); + + ublas::vector Q_avg = _Q_avg; + if(bCenterOn0) + Q_avg = ublas::zero_vector(Q_avg.size()); + + for(unsigned int i=0; i vecWProj(3), vecWSlice(3); + ublas::vector vecOffsProj(3), vecOffsSlice(3); + + vecWProj[0] = m_elliProj[i].x_hwhm; + vecWProj[1] = m_elliProj[i].y_hwhm; + vecWProj[2] = m_elliProj[i].z_hwhm; + + vecWSlice[0] = m_elliSlice[i].x_hwhm; + vecWSlice[1] = m_elliSlice[i].y_hwhm; + vecWSlice[2] = m_elliSlice[i].z_hwhm; + + vecOffsProj[0] = m_elliProj[i].x_offs; + vecOffsProj[1] = m_elliProj[i].y_offs; + vecOffsProj[2] = m_elliProj[i].z_offs; + + vecOffsSlice[0] = m_elliSlice[i].x_offs; + vecOffsSlice[1] = m_elliSlice[i].y_offs; + vecOffsSlice[2] = m_elliSlice[i].z_offs; + + /*if(i==1) + { + std::cout << "widths: " << vecWProj << std::endl; + std::cout << "offs: " << vecOffsProj << std::endl; + std::cout << "rot: " << m_elliProj[i].rot << std::endl; + }*/ + m_pPlots[i]->PlotEllipsoid(vecWProj, vecOffsProj, m_elliProj[i].rot, 1); + m_pPlots[i]->PlotEllipsoid(vecWSlice, vecOffsSlice, m_elliSlice[i].rot, 0); + + m_pPlots[i]->SetObjectUseLOD(1, 0); + m_pPlots[i]->SetObjectUseLOD(0, 0); + + m_pPlots[i]->SetMinMax(ProjRotatedVec(m_elliProj[i].rot, vecWProj), &vecOffsProj); + + const std::string& strX = ellipse_labels(iX[i], coord); + const std::string& strY = ellipse_labels(iY[i], coord); + const std::string& strZ = ellipse_labels(iZ[i], coord); + m_pPlots[i]->SetLabels(strX.c_str(), strY.c_str(), strZ.c_str()); + } +} + +void EllipseDlg3D::SetParams(const EllipseDlgParams& params) +{ + static const ublas::matrix mat0 = ublas::zero_matrix(4,4); + static const ublas::vector vec0 = ublas::zero_vector(4); + + if(params.reso) m_reso = *params.reso; else m_reso = mat0; + if(params.reso_v) m_reso_v = *params.reso_v; else m_reso_v = vec0; + m_reso_s = params.reso_s; + if(params.Q_avg) m_Q_avg = *params.Q_avg; else m_Q_avg = vec0; + + if(params.resoHKL) m_resoHKL = *params.resoHKL; else m_resoHKL = mat0; + if(params.reso_vHKL) m_reso_vHKL = *params.reso_vHKL; else m_reso_vHKL = vec0; + if(params.Q_avgHKL) m_Q_avgHKL = *params.Q_avgHKL; else m_Q_avgHKL = vec0; + + if(params.resoOrient) m_resoOrient = *params.resoOrient; else m_resoOrient = mat0; + if(params.reso_vOrient) m_reso_vOrient = *params.reso_vOrient; else m_reso_vOrient = vec0; + if(params.Q_avgOrient) m_Q_avgOrient = *params.Q_avgOrient; else m_Q_avgOrient = vec0; + + m_algo = params.algo; + + Calc(); +} + +#include "EllipseDlg3D.moc" diff --git a/dialogs/EllipseDlg3D.h b/dialogs/EllipseDlg3D.h new file mode 100644 index 0000000..ea733c4 --- /dev/null +++ b/dialogs/EllipseDlg3D.h @@ -0,0 +1,60 @@ +/* + * 3D Ellipsoid Dialog + * @author Tobias Weber + * @date may-2013, 29-apr-2014 + * @license GPLv2 + */ + +#ifndef __RESO_ELLI_DLG_3D__ +#define __RESO_ELLI_DLG_3D__ + +#include +#include +#include + +#include + +#include "EllipseDlg.h" +#include "libs/plotgl.h" +#include "tlibs/math/linalg.h" +#include "tools/res/ellipse.h" +#include "tools/res/defs.h" + + +class EllipseDlg3D : public QDialog +{Q_OBJECT + protected: + std::vector m_pPlots; + std::vector> m_elliProj; + std::vector> m_elliSlice; + + QComboBox *m_pComboCoord = nullptr; + QSettings *m_pSettings = nullptr; + + ublas::matrix m_reso, m_resoHKL, m_resoOrient; + ublas::vector m_reso_v = ublas::zero_vector(4), + m_reso_vHKL = ublas::zero_vector(4), + m_reso_vOrient = ublas::zero_vector(4); + t_real_reso m_reso_s = 0; + ublas::vector m_Q_avg, m_Q_avgHKL, m_Q_avgOrient; + ResoAlgo m_algo = ResoAlgo::UNKNOWN; + + protected: + ublas::vector + ProjRotatedVec(const ublas::matrix& rot, + const ublas::vector& vec); + + public: + EllipseDlg3D(QWidget* pParent, QSettings *pSett=0); + virtual ~EllipseDlg3D(); + + protected: + void hideEvent(QHideEvent *event); + void showEvent(QShowEvent *event); + + public slots: + void SetParams(const EllipseDlgParams& params); + void Calc(); +}; + +#endif diff --git a/dialogs/FilePreviewDlg.cpp b/dialogs/FilePreviewDlg.cpp new file mode 100644 index 0000000..cf8be60 --- /dev/null +++ b/dialogs/FilePreviewDlg.cpp @@ -0,0 +1,107 @@ +/* + * File Preview Dialog + * @author Tobias Weber + * @date feb-2015 + * @license GPLv2 + */ + +#include "FilePreviewDlg.h" +#include +#include +#include "tlibs/file/loadinstr.h" +#include +#include + +using t_real = t_real_glob; + + +FilePreviewDlg::FilePreviewDlg(QWidget* pParent, const char* pcTitle, QSettings* pSett) + : QFileDialog(pParent, pcTitle), m_pSettings(pSett) +{ + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + m_pPlot.reset(new QwtPlot()); + m_plotwrap.reset(new QwtPlotWrapper(m_pPlot.get(), 2, true)); + + QPen penCurve; + penCurve.setColor(QColor(0,0,0x99)); + penCurve.setWidth(2); + m_plotwrap->GetCurve(0)->setPen(penCurve); + m_plotwrap->GetCurve(0)->setStyle(QwtPlotCurve::CurveStyle::Lines); + m_plotwrap->GetCurve(0)->setTitle("Scan Curve"); + + QPen penPoints; + penPoints.setColor(QColor(0xff,0,0)); + penPoints.setWidth(4); + m_plotwrap->GetCurve(1)->setPen(penPoints); + m_plotwrap->GetCurve(1)->setStyle(QwtPlotCurve::CurveStyle::Dots); + m_plotwrap->GetCurve(1)->setTitle("Scan Points"); + + QSizePolicy spol(QSizePolicy::Preferred, QSizePolicy::Preferred); + spol.setHorizontalStretch(1); + spol.setVerticalStretch(1); + m_pPlot->setSizePolicy(spol); + + // depends on qt/src/gui/dialogs/qfiledialog.ui using QGridLayout + QGridLayout *pLayout((QGridLayout*)layout()); + pLayout->addWidget(m_pPlot.get(), pLayout->rowCount(), 0, 1, pLayout->columnCount()); + resize(size().width(), size().height()*1.25); + +#if QT_VER >= 5 + QObject::connect(this, &FilePreviewDlg::currentChanged, + this, &FilePreviewDlg::FileSelected); +#else + QObject::connect(this, SIGNAL(currentChanged(const QString&)), + this, SLOT(FileSelected(const QString&))); +#endif +} + +FilePreviewDlg::~FilePreviewDlg() {} + +void FilePreviewDlg::ClearPlot() +{ + m_vecCts.clear(); + m_vecScn.clear(); + + set_qwt_data()(*m_plotwrap, m_vecScn, m_vecCts, 0, 0); + set_qwt_data()(*m_plotwrap, m_vecScn, m_vecCts, 1, 0); + + m_pPlot->setAxisTitle(QwtPlot::xBottom, ""); + m_pPlot->setAxisTitle(QwtPlot::yLeft, ""); + + m_pPlot->replot(); +} + +void FilePreviewDlg::FileSelected(const QString& qstrFile) +{ + ClearPlot(); + + tl::FileInstrBase *pInstr = tl::FileInstrBase::LoadInstr(qstrFile.toStdString().c_str()); + if(!pInstr) return; + + std::unique_ptr> _ptrInstr(pInstr); + + std::vector vecScanVars = pInstr->GetScannedVars(); + if(vecScanVars.size() == 0) return; + m_vecCts = pInstr->GetCol(pInstr->GetCountVar()); + m_vecScn = pInstr->GetCol(vecScanVars[0]); + + //std::copy(m_vecScn.begin(), m_vecScn.end(), std::ostream_iterator(std::cout, " ")); + //std::cout << std::endl; + + set_qwt_data()(*m_plotwrap, m_vecScn, m_vecCts, 0, 0); + set_qwt_data()(*m_plotwrap, m_vecScn, m_vecCts, 1, 0); + + m_pPlot->setAxisTitle(QwtPlot::xBottom, vecScanVars[0].c_str()); + m_pPlot->setAxisTitle(QwtPlot::yLeft, "Counts"); + + m_pPlot->replot(); +} + + +#include "FilePreviewDlg.moc" diff --git a/dialogs/FilePreviewDlg.h b/dialogs/FilePreviewDlg.h new file mode 100644 index 0000000..ba0cda7 --- /dev/null +++ b/dialogs/FilePreviewDlg.h @@ -0,0 +1,45 @@ +/* + * File Preview Dialog + * @author Tobias Weber + * @date feb-2015 + * @license GPLv2 + */ + +#ifndef __FILE_PREV_DLG__ +#define __FILE_PREV_DLG__ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "libs/qthelper.h" +#include "libs/globals.h" + + +class FilePreviewDlg : public QFileDialog +{ Q_OBJECT + protected: + QSettings *m_pSettings = nullptr; + + std::unique_ptr m_pPlot; + std::unique_ptr m_plotwrap; + std::vector m_vecScn, m_vecCts; + + protected: + void ClearPlot(); + + public: + FilePreviewDlg(QWidget* pParent, const char* pcTitle, QSettings* pSett=0); + virtual ~FilePreviewDlg(); + + protected slots: + void FileSelected(const QString& strFile); +}; + +#endif diff --git a/dialogs/FormfactorDlg.cpp b/dialogs/FormfactorDlg.cpp new file mode 100644 index 0000000..6ce49a9 --- /dev/null +++ b/dialogs/FormfactorDlg.cpp @@ -0,0 +1,445 @@ +/** + * Form Factor & Scattering Length Dialog + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#include "FormfactorDlg.h" +#include "libs/formfactors/formfact.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/math/term.h" +#include "libs/qthelper.h" + +#include + +using t_real = t_real_glob; + + +FormfactorDlg::FormfactorDlg(QWidget* pParent, QSettings *pSettings) + : QDialog(pParent), m_pSettings(pSettings) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + SetupAtoms(); + SetupMagAtoms(); + + // form factors + m_plotwrap.reset(new QwtPlotWrapper(plotF)); + m_plotwrap->GetCurve(0)->setTitle("Atomic Form Factor"); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Scattering Wavenumber Q (1/A)"); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Atomic Form Factor f (e-)"); + if(m_plotwrap->HasTrackerSignal()) + connect(m_plotwrap->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + // mag. form factors + m_plotwrap_m.reset(new QwtPlotWrapper(plotMF)); + m_plotwrap_m->GetCurve(0)->setTitle("Magnetic Form Factor"); + m_plotwrap_m->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Scattering Wavenumber Q (1/A)"); + m_plotwrap_m->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Magnetic Form Factor"); + if(m_plotwrap_m->HasTrackerSignal()) + connect(m_plotwrap_m->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + // scattering lengths + m_plotwrapSc.reset(new QwtPlotWrapper(plotSc)); + m_plotwrapSc->GetCurve(0)->setTitle("Scattering Lengths"); + m_plotwrapSc->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Element"); + m_plotwrapSc->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Scattering Length b (fm)"); + if(m_plotwrapSc->HasTrackerSignal()) + connect(m_plotwrapSc->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + + // connections + QObject::connect(listAtoms, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(AtomSelected(QListWidgetItem*, QListWidgetItem*))); + QObject::connect(editFilter, SIGNAL(textEdited(const QString&)), + this, SLOT(SearchAtom(const QString&))); + + QObject::connect(listMAtoms, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(MagAtomSelected(QListWidgetItem*, QListWidgetItem*))); + QObject::connect(editMFilter, SIGNAL(textEdited(const QString&)), + this, SLOT(SearchMagAtom(const QString&))); + QObject::connect(spinL, SIGNAL(valueChanged(double)), this, SLOT(RefreshMagAtom())); + QObject::connect(spinS, SIGNAL(valueChanged(double)), this, SLOT(RefreshMagAtom())); + QObject::connect(spinJ, SIGNAL(valueChanged(double)), this, SLOT(RefreshMagAtom())); + + QObject::connect(editOrbital, SIGNAL(textEdited(const QString&)), + this, SLOT(CalcTermSymbol(const QString&))); + + QObject::connect(radioCoherent, SIGNAL(toggled(bool)), + this, SLOT(PlotScatteringLengths())); + QObject::connect(editSLSearch, SIGNAL(textEdited(const QString&)), + this, SLOT(SearchSLAtom(const QString&))); + + + if(m_pSettings && m_pSettings->contains("formfactors/geo")) + restoreGeometry(m_pSettings->value("formfactors/geo").toByteArray()); + + + SearchAtom("H"); + //radioCoherent->setChecked(1); + SetupScatteringLengths(); + PlotScatteringLengths(); +} + +FormfactorDlg::~FormfactorDlg() +{} + + +static QListWidgetItem* create_header_item(const char *pcTitle, bool bSubheader=0) +{ + QListWidgetItem *pHeaderItem = new QListWidgetItem(pcTitle); + pHeaderItem->setTextAlignment(Qt::AlignHCenter); + + QFont fontHeader = pHeaderItem->font(); + fontHeader.setBold(1); + pHeaderItem->setFont(fontHeader); + + QBrush brushHeader = pHeaderItem->foreground(); + brushHeader.setColor(QColor(0xff, 0xff, 0xff)); + pHeaderItem->setForeground(brushHeader); + + pHeaderItem->setData(Qt::UserRole, 0); + pHeaderItem->setBackgroundColor(bSubheader ? QColor(0x85, 0x85, 0x85) : QColor(0x65, 0x65, 0x65)); + + return pHeaderItem; +} + + +void FormfactorDlg::SetupAtoms() +{ + std::shared_ptr> lstff = FormfactList::GetInstance(); + listAtoms->addItem(create_header_item("Atoms")); + for(unsigned int iFF=0; iFFGetNumAtoms(); ++iFF) + { + if(iFF==0) listAtoms->addItem(create_header_item("Period 1", 1)); + else if(iFF==2) listAtoms->addItem(create_header_item("Period 2", 1)); + else if(iFF==10) listAtoms->addItem(create_header_item("Period 3", 1)); + else if(iFF==18) listAtoms->addItem(create_header_item("Period 4", 1)); + else if(iFF==36) listAtoms->addItem(create_header_item("Period 5", 1)); + else if(iFF==54) listAtoms->addItem(create_header_item("Period 6", 1)); + else if(iFF==86) listAtoms->addItem(create_header_item("Period 7", 1)); + + const Formfact& ff = lstff->GetAtom(iFF); + const std::string& strAtom = ff.GetAtomIdent(); + + std::ostringstream ostrAtom; + ostrAtom << (iFF+1) << " " << strAtom; + QListWidgetItem* pItem = new QListWidgetItem(ostrAtom.str().c_str()); + pItem->setData(Qt::UserRole, 1); + pItem->setData(Qt::UserRole+1, iFF); + listAtoms->addItem(pItem); + } + + listAtoms->addItem(create_header_item("Ions")); + for(unsigned int iFF=0; iFFGetNumIons(); ++iFF) + { + const Formfact& ff = lstff->GetIon(iFF); + const std::string& strAtom = ff.GetAtomIdent(); + + std::ostringstream ostrAtom; + ostrAtom << strAtom; + QListWidgetItem* pItem = new QListWidgetItem(ostrAtom.str().c_str()); + pItem->setData(Qt::UserRole, 2); + pItem->setData(Qt::UserRole+1, iFF); + listAtoms->addItem(pItem); + } +} + +void FormfactorDlg::SetupMagAtoms() +{ + std::shared_ptr> lstff = MagFormfactList::GetInstance(); + listMAtoms->addItem(create_header_item("Atoms / Ions")); + + bool bHad3d=0, bHad4d=0, bHad4f=0, bHad5f=0; + for(unsigned int iFF=0; iFFGetNumAtoms(); ++iFF) + { + const MagFormfact& ff = lstff->GetAtom(iFF); + const std::string& strAtom = ff.GetAtomIdent(); + + if(strAtom.find("Sc") != std::string::npos && !bHad3d) + { + listMAtoms->addItem(create_header_item("3d (4s) Orbitals", 1)); + bHad3d = 1; + } + if(strAtom.find("Y") != std::string::npos && !bHad4d) + { + listMAtoms->addItem(create_header_item("4d (5s) Orbitals", 1)); + bHad4d = 1; + } + if(strAtom.find("Ce") != std::string::npos && !bHad4f) + { + listMAtoms->addItem(create_header_item("4f (5d 6s) Orbitals", 1)); + bHad4f = 1; + } + if((strAtom.find("Pa")!=std::string::npos || strAtom.find("U")!=std::string::npos) + && !bHad5f) + { + listMAtoms->addItem(create_header_item("5f (6d 7s) Orbitals", 1)); + bHad5f = 1; + } + + std::ostringstream ostrAtom; + ostrAtom << (iFF+1) << " " << strAtom; + QListWidgetItem* pItem = new QListWidgetItem(ostrAtom.str().c_str()); + pItem->setData(Qt::UserRole, 1); + pItem->setData(Qt::UserRole+1, iFF); + listMAtoms->addItem(pItem); + } +} + + +void FormfactorDlg::AtomSelected(QListWidgetItem *pItem, QListWidgetItem*) +{ + if(!pItem) return; + const unsigned int iAtomOrIon = pItem->data(Qt::UserRole).toUInt(); + if(iAtomOrIon == 0) return; + const unsigned int iAtom = pItem->data(Qt::UserRole+1).toUInt(); + + const unsigned int NUM_POINTS = 512; + + t_real dMinQ = 0.; + t_real dMaxQ = 25.; + + m_vecQ.clear(); + m_vecFF.clear(); + + m_vecQ.reserve(NUM_POINTS); + m_vecFF.reserve(NUM_POINTS); + + std::shared_ptr> lstff = FormfactList::GetInstance(); + if((iAtomOrIon==1 && iAtom < lstff->GetNumAtoms()) || + (iAtomOrIon==2 && iAtom < lstff->GetNumIons())) + { + const Formfact& ff = (iAtomOrIon==1 ? lstff->GetAtom(iAtom) : lstff->GetIon(iAtom)); + + for(unsigned int iPt=0; iPt()(*m_plotwrap, m_vecQ, m_vecFF); +} + +void FormfactorDlg::MagAtomSelected(QListWidgetItem *pItem, QListWidgetItem*) +{ + if(!pItem || !pItem->data(Qt::UserRole).toUInt()) return; + const unsigned int iAtom = pItem->data(Qt::UserRole+1).toUInt(); + const unsigned int NUM_POINTS = 512; + + t_real dMinQ = 0.; + t_real dMaxQ = 15.; + + m_vecQ_m.clear(); + m_vecFF_m.clear(); + + m_vecQ_m.reserve(NUM_POINTS); + m_vecFF_m.reserve(NUM_POINTS); + + t_real dL = spinL->value(); + t_real dS = spinS->value(); + t_real dJ = spinJ->value(); + + std::shared_ptr> lstff = MagFormfactList::GetInstance(); + if(iAtom >= lstff->GetNumAtoms()) return; + + const MagFormfact& ff = lstff->GetAtom(iAtom); + + for(unsigned int iPt=0; iPt()(*m_plotwrap_m, m_vecQ_m, m_vecFF_m); +} + +void FormfactorDlg::RefreshMagAtom() +{ + MagAtomSelected(listMAtoms->currentItem(), nullptr); +} + + +void FormfactorDlg::CalcTermSymbol(const QString& qstr) +{ + try + { + std::string strOrbitals = qstr.toStdString(); + + t_real dS, dL, dJ; + std::tie(dS,dL,dJ) = tl::hund(strOrbitals); + + spinS->setValue(dS); + spinL->setValue(dL); + spinJ->setValue(dJ); + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + } +} + + +void FormfactorDlg::SearchAtom(const QString& qstr) +{ + QList lstItems = listAtoms->findItems(qstr, Qt::MatchContains); + if(lstItems.size()) + listAtoms->setCurrentItem(lstItems[0], QItemSelectionModel::SelectCurrent); +} + +void FormfactorDlg::SearchMagAtom(const QString& qstr) +{ + QList lstItems = listMAtoms->findItems(qstr, Qt::MatchContains); + if(lstItems.size()) + listMAtoms->setCurrentItem(lstItems[0], QItemSelectionModel::SelectCurrent); +} + +void FormfactorDlg::SearchSLAtom(const QString& qstr) +{ + QList lstItems = tableSL->findItems(qstr, Qt::MatchContains); + if(lstItems.size()) + tableSL->setCurrentItem(lstItems[0]); +} + + +void FormfactorDlg::PlotScatteringLengths() +{ + const bool bCoh = radioCoherent->isChecked(); + + m_vecElem.clear(); + m_vecSc.clear(); + + std::shared_ptr> lstsc = ScatlenList::GetInstance(); + for(unsigned int iAtom=0; iAtomGetNumElems(); ++iAtom) + { + const ScatlenList::elem_type& sc = lstsc->GetElem(iAtom); + std::complex b = bCoh ? sc.GetCoherent() : sc.GetIncoherent(); + + m_vecElem.push_back(t_real(iAtom+1)); + m_vecSc.push_back(b.real()); + } + + set_qwt_data()(*m_plotwrapSc, m_vecElem, m_vecSc); +} + + +enum +{ + SL_ITEM_NR = 0, + SL_ITEM_NAME = 1, + SL_ITEM_COH_R = 2, + SL_ITEM_COH_I = 3, + SL_ITEM_INC_R = 4, + SL_ITEM_INC_I = 5, +}; + +void FormfactorDlg::SetupScatteringLengths() +{ + std::shared_ptr> lstsc = ScatlenList::GetInstance(); + + const bool bSortTable = tableSL->isSortingEnabled(); + tableSL->setSortingEnabled(0); + + tableSL->setRowCount(lstsc->GetNumElems() + lstsc->GetNumIsotopes()); + tableSL->setColumnWidth(SL_ITEM_NR, 50); + tableSL->setColumnWidth(SL_ITEM_NAME, 70); + tableSL->setColumnWidth(SL_ITEM_COH_R, 75); + tableSL->setColumnWidth(SL_ITEM_COH_I, 75); + tableSL->setColumnWidth(SL_ITEM_INC_R, 75); + tableSL->setColumnWidth(SL_ITEM_INC_I, 75); + + tableSL->verticalHeader()->setDefaultSectionSize(tableSL->verticalHeader()->minimumSectionSize()+2); + + for(std::size_t iElem=0; iElemGetNumElems()+lstsc->GetNumIsotopes(); ++iElem) + { + const typename ScatlenList::elem_type* pelem = nullptr; + if(iElem < lstsc->GetNumElems()) + pelem = &lstsc->GetElem(iElem); + else + pelem = &lstsc->GetIsotope(iElem-lstsc->GetNumElems()); + + t_real dCohR = pelem->GetCoherent().real(); + t_real dCohI = pelem->GetCoherent().imag(); + t_real dIncR = pelem->GetIncoherent().real(); + t_real dIncI = pelem->GetIncoherent().imag(); + + std::string strCohR = tl::var_to_str(dCohR, g_iPrec) + " fm"; + std::string strCohI = tl::var_to_str(dCohI, g_iPrec) + " fm"; + std::string strIncR = tl::var_to_str(dIncR, g_iPrec) + " fm"; + std::string strIncI = tl::var_to_str(dIncI, g_iPrec) + " fm"; + + tableSL->setItem(iElem, SL_ITEM_NR, new QTableWidgetItemWrapper(iElem+1)); + tableSL->setItem(iElem, SL_ITEM_NAME, new QTableWidgetItem(pelem->GetAtomIdent().c_str())); + tableSL->setItem(iElem, SL_ITEM_COH_R, new QTableWidgetItemWrapper(dCohR, strCohR)); + tableSL->setItem(iElem, SL_ITEM_COH_I, new QTableWidgetItemWrapper(dCohI, strCohI)); + tableSL->setItem(iElem, SL_ITEM_INC_R, new QTableWidgetItemWrapper(dIncR, strIncR)); + tableSL->setItem(iElem, SL_ITEM_INC_I, new QTableWidgetItemWrapper(dIncI, strIncI)); + } + + tableSL->setSortingEnabled(bSortTable); + tableSL->sortByColumn(SL_ITEM_NR, Qt::AscendingOrder); +} + + +void FormfactorDlg::cursorMoved(const QPointF& pt) +{ + if(tabWidget->currentIndex() == 1) + { + std::wstring strX = std::to_wstring(pt.x()); + std::wstring strY = std::to_wstring(pt.y()); + + const std::wstring strAA = tl::get_spec_char_utf16("AA") + + tl::get_spec_char_utf16("sup-") + + tl::get_spec_char_utf16("sup1"); + + std::wostringstream ostr; + ostr << L"Q = " << strX << L" " << strAA; + ostr << L", f = " << strY; + + labelStatus->setText(QString::fromWCharArray(ostr.str().c_str())); + } + else if(tabWidget->currentIndex() == 0) + { + std::shared_ptr> lst = ScatlenList::GetInstance(); + + int iElem = std::round(pt.x()); + if(iElem<=0 || iElem>=int(lst->GetNumElems())) + { + labelStatus->setText(""); + return; + } + + const std::string& strName = lst->GetElem(unsigned(iElem-1)).GetAtomIdent(); + std::complex b_coh = lst->GetElem(unsigned(iElem-1)).GetCoherent(); + std::complex b_inc = lst->GetElem(unsigned(iElem-1)).GetIncoherent(); + + std::ostringstream ostr; + ostr << iElem << ", " << strName + << ": b_coh = " << b_coh << ", b_inc = " << b_inc; + labelStatus->setText(ostr.str().c_str()); + } +} + + +void FormfactorDlg::closeEvent(QCloseEvent* pEvt) +{ + if(m_pSettings) + m_pSettings->setValue("formfactors/geo", saveGeometry()); +} + + +#include "FormfactorDlg.moc" diff --git a/dialogs/FormfactorDlg.h b/dialogs/FormfactorDlg.h new file mode 100644 index 0000000..cc6ddcb --- /dev/null +++ b/dialogs/FormfactorDlg.h @@ -0,0 +1,64 @@ +/** + * Form Factor & Scattering Length Dialog + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_FF_DLG_H__ +#define __TAKIN_FF_DLG_H__ + +#include +#include +#include +#include +#include "ui/ui_formfactors.h" +#include "libs/qthelper.h" +#include "libs/globals.h" + + +class FormfactorDlg : public QDialog, Ui::FormFactorDlg +{ Q_OBJECT +protected: + QSettings *m_pSettings = nullptr; + + // form factors + std::vector m_vecQ, m_vecFF; + std::unique_ptr m_plotwrap; + + // mag form factors + std::vector m_vecQ_m, m_vecFF_m; + std::unique_ptr m_plotwrap_m; + + // scattering lengths + std::vector m_vecElem, m_vecSc; + std::unique_ptr m_plotwrapSc; + + +protected: + virtual void closeEvent(QCloseEvent* pEvt) override; + + void SetupAtoms(); + void SetupMagAtoms(); + +protected slots: + void SearchAtom(const QString& qstr); + void AtomSelected(QListWidgetItem *pItem, QListWidgetItem *pItemPrev); + + void SearchMagAtom(const QString& qstr); + void MagAtomSelected(QListWidgetItem *pItem, QListWidgetItem *pItemPrev); + void RefreshMagAtom(); + void CalcTermSymbol(const QString& qstr); + + void SearchSLAtom(const QString& qstr); + void PlotScatteringLengths(); + void SetupScatteringLengths(); + + void cursorMoved(const QPointF& pt); + +public: + FormfactorDlg(QWidget* pParent = nullptr, QSettings *pSettings = nullptr); + virtual ~FormfactorDlg(); +}; + +#endif diff --git a/dialogs/GotoDlg.cpp b/dialogs/GotoDlg.cpp new file mode 100644 index 0000000..df6a187 --- /dev/null +++ b/dialogs/GotoDlg.cpp @@ -0,0 +1,741 @@ +/* + * Goto Dialog + * @author Tobias Weber + * @date 15-oct-2014 + * @license GPLv2 + */ + +#include "GotoDlg.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" + +#include +#include + +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_angle_si rads = tl::get_one_radian(); + + +GotoDlg::GotoDlg(QWidget* pParent, QSettings* pSett) : QDialog(pParent), m_pSettings(pSett) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + btnAdd->setIcon(load_icon("res/list-add.svg")); + btnDel->setIcon(load_icon("res/list-remove.svg")); + btnSave->setIcon(load_icon("res/document-save.svg")); + btnLoad->setIcon(load_icon("res/document-open.svg")); + + std::vector vecObjs {editH, editK, editL}; + std::vector vecAngles {edit2ThetaM, editThetaM, edit2ThetaA, editThetaA, edit2ThetaS, editThetaS}; + +#if QT_VER >= 5 + QObject::connect(buttonBox, &QDialogButtonBox::clicked, this, &GotoDlg::ButtonBoxClicked); + + QObject::connect(btnAdd, &QAbstractButton::clicked, this, static_cast(&GotoDlg::AddPosToList)); + QObject::connect(btnDel, &QAbstractButton::clicked, this, &GotoDlg::RemPosFromList); + QObject::connect(btnLoad, &QAbstractButton::clicked, this, &GotoDlg::LoadList); + QObject::connect(btnSave, &QAbstractButton::clicked, this, &GotoDlg::SaveList); + QObject::connect(listSeq, &QListWidget::itemSelectionChanged, this, &GotoDlg::ListItemSelected); + QObject::connect(listSeq, &QListWidget::itemDoubleClicked, this, &GotoDlg::ListItemDoubleClicked); + + QObject::connect(editKi, &QLineEdit::textEdited, this, &GotoDlg::EditedKiKf); + QObject::connect(editKf, &QLineEdit::textEdited, this, &GotoDlg::EditedKiKf); + QObject::connect(editE, &QLineEdit::textEdited, this, &GotoDlg::EditedE); + QObject::connect(btnGetPos, &QAbstractButton::clicked, this, &GotoDlg::GetCurPos); + + for(QLineEdit* pObj : vecObjs) + QObject::connect(pObj, &QLineEdit::textEdited, this, &GotoDlg::CalcSample); + for(QLineEdit* pObj : vecAngles) + QObject::connect(pObj, &QLineEdit::textEdited, this, &GotoDlg::EditedAngles); +#else + QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(ButtonBoxClicked(QAbstractButton*))); + + QObject::connect(btnAdd, SIGNAL(clicked()), this, SLOT(AddPosToList())); + QObject::connect(btnDel, SIGNAL(clicked()), this, SLOT(RemPosFromList())); + QObject::connect(btnLoad, SIGNAL(clicked()), this, SLOT(LoadList())); + QObject::connect(btnSave, SIGNAL(clicked()), this, SLOT(SaveList())); + QObject::connect(listSeq, SIGNAL(itemSelectionChanged()), this, SLOT(ListItemSelected())); + QObject::connect(listSeq, SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this, SLOT(ListItemDoubleClicked(QListWidgetItem*))); + + QObject::connect(editKi, SIGNAL(textEdited(const QString&)), this, SLOT(EditedKiKf())); + QObject::connect(editKf, SIGNAL(textEdited(const QString&)), this, SLOT(EditedKiKf())); + QObject::connect(editE, SIGNAL(textEdited(const QString&)), this, SLOT(EditedE())); + QObject::connect(btnGetPos, SIGNAL(clicked()), this, SLOT(GetCurPos())); + + for(QObject* pObj : vecObjs) + QObject::connect(pObj, SIGNAL(textEdited(const QString&)), this, SLOT(CalcSample())); + for(QObject* pObj : vecAngles) + QObject::connect(pObj, SIGNAL(textEdited(const QString&)), this, SLOT(EditedAngles())); +#endif + + if(m_pSettings) + { + if(m_pSettings->contains("goto_pos/geo")) + restoreGeometry(m_pSettings->value("goto_pos/geo").toByteArray()); + if(m_pSettings->contains("goto_pos/ki_fix")) + radioFixedKi->setChecked(m_pSettings->value("goto_pos/ki_fix").toBool()); + } +} + +GotoDlg::~GotoDlg() +{ + ClearList(); +} + + +void GotoDlg::CalcSample() +{ + m_bSampleOk = 0; + + std::vector vecEdits{editThetaS, edit2ThetaS}; + for(QLineEdit* pEdit : vecEdits) + pEdit->setText(""); + + bool bHOk=0, bKOk=0, bLOk=0, bKiOk=0, bKfOk=0; + + t_real dH = editH->text().toDouble(&bHOk); + t_real dK = editK->text().toDouble(&bKOk); + t_real dL = editL->text().toDouble(&bLOk); + t_real dKi = editKi->text().toDouble(&bKiOk); + t_real dKf = editKf->text().toDouble(&bKfOk); + + if(!bHOk || !bKOk || !bLOk || !bKiOk || !bKfOk) + return; + + ublas::vector vecQ; + bool bFailed = 0; + try + { + tl::get_tas_angles(m_lattice, + m_vec1, m_vec2, + dKi, dKf, + dH, dK, dL, + m_bSenseS, + &m_dSampleTheta, &m_dSample2Theta, + &vecQ); + + if(tl::is_nan_or_inf(m_dSample2Theta)) + throw tl::Err("Invalid sample 2theta."); + if(tl::is_nan_or_inf(m_dSampleTheta)) + throw tl::Err("Invalid sample theta."); + } + catch(const std::exception& ex) + { + editThetaS->setText("invalid"); + edit2ThetaS->setText("invalid"); + + //log_err(ex.what()); + labelStatus->setText((std::string("Error: ") + ex.what()).c_str()); + bFailed = 1; + } + + tl::set_eps_0(vecQ, g_dEps); + tl::set_eps_0(m_dSample2Theta, g_dEps); + tl::set_eps_0(m_dSampleTheta, g_dEps); + + const std::wstring strAA = tl::get_spec_char_utf16("AA") + tl::get_spec_char_utf16("sup-") + tl::get_spec_char_utf16("sup1"); + + std::wostringstream ostrStatus; + ostrStatus << "Q = " << vecQ << " " << strAA << ", |Q| = " << ublas::norm_2(vecQ) << " " << strAA; + labelQ->setText(QString::fromWCharArray(ostrStatus.str().c_str())); + +#ifndef NDEBUG + try + { + ublas::vector vecQ0 = vecQ; + vecQ0.resize(2, true); + t_real dAngleQVec0 = tl::r2d(tl::vec_angle(vecQ0)); + tl::log_info("Angle Q Orient0: ", dAngleQVec0, " deg."); + } + catch(const std::exception& ex) + {} +#endif + + if(bFailed) return; + + editThetaS->setText(tl::var_to_str(tl::r2d(m_dSampleTheta), g_iPrec).c_str()); + edit2ThetaS->setText(tl::var_to_str(tl::r2d(m_dSample2Theta), g_iPrec).c_str()); + + m_bSampleOk = 1; + + if(m_bMonoAnaOk && m_bSampleOk) + labelStatus->setText("Position OK."); +} + +void GotoDlg::CalcMonoAna() +{ + m_bMonoAnaOk = 0; + + std::vector vecEdits{editThetaM, edit2ThetaM, editThetaA, edit2ThetaA}; + for(QLineEdit* pEdit : vecEdits) + pEdit->setText(""); + + bool bKiOk=0, bKfOk=0; + t_real dKi = editKi->text().toDouble(&bKiOk); + t_real dKf = editKf->text().toDouble(&bKfOk); + if(!bKiOk || !bKfOk) return; + + tl::t_wavenumber_si ki = dKi / angs; + tl::t_wavenumber_si kf = dKf / angs; + + bool bMonoOk = 0; + bool bAnaOk = 0; + + try + { + m_dMono2Theta = tl::get_mono_twotheta(ki, m_dMono*angs, m_bSenseM) / rads; + if(tl::is_nan_or_inf(m_dMono2Theta)) + throw tl::Err("Invalid monochromator angle."); + + tl::set_eps_0(m_dMono2Theta, g_dEps); + bMonoOk = 1; + } + catch(const std::exception& ex) + { + editThetaM->setText("invalid"); + edit2ThetaM->setText("invalid"); + + //log_err(ex.what()); + labelStatus->setText((std::string("Error: ") + ex.what()).c_str()); + } + + try + { + m_dAna2Theta = tl::get_mono_twotheta(kf, m_dAna*angs, m_bSenseA) / rads; + if(tl::is_nan_or_inf(m_dAna2Theta)) + throw tl::Err("Invalid analysator angle."); + + tl::set_eps_0(m_dAna2Theta, g_dEps); + bAnaOk = 1; + } + catch(const std::exception& ex) + { + editThetaA->setText("invalid"); + edit2ThetaA->setText("invalid"); + + //log_err(ex.what()); + labelStatus->setText((std::string("Error: ") + ex.what()).c_str()); + } + + if(!bMonoOk || !bAnaOk) + return; + + + t_real dTMono = m_dMono2Theta / 2.; + t_real dTAna = m_dAna2Theta / 2.; + + edit2ThetaM->setText(tl::var_to_str(tl::r2d(m_dMono2Theta), g_iPrec).c_str()); + editThetaM->setText(tl::var_to_str(tl::r2d(dTMono), g_iPrec).c_str()); + edit2ThetaA->setText(tl::var_to_str(tl::r2d(m_dAna2Theta), g_iPrec).c_str()); + editThetaA->setText(tl::var_to_str(tl::r2d(dTAna), g_iPrec).c_str()); + + m_bMonoAnaOk = 1; + + if(m_bMonoAnaOk && m_bSampleOk) + labelStatus->setText("Position OK."); +} + +void GotoDlg::EditedKiKf() +{ + bool bKiOk=0, bKfOk=0; + t_real dKi = editKi->text().toDouble(&bKiOk); + t_real dKf = editKf->text().toDouble(&bKfOk); + if(!bKiOk || !bKfOk) return; + + tl::t_energy_si Ei = tl::k2E(dKi / angs); + tl::t_energy_si Ef = tl::k2E(dKf / angs); + + tl::t_energy_si E = Ei-Ef; + t_real dE = E/meV; + tl::set_eps_0(dE, g_dEps); + + std::string strE = tl::var_to_str(dE, g_iPrec); + editE->setText(strE.c_str()); + + CalcMonoAna(); + CalcSample(); +} + +void GotoDlg::EditedE() +{ + bool bOk = 0; + t_real dE = editE->text().toDouble(&bOk); + if(!bOk) return; + tl::t_energy_si E = dE * meV; + + bool bImag=0; + tl::t_wavenumber_si k_E = tl::E2k(E, bImag); + t_real dSign = 1.; + if(bImag) dSign = -1.; + + if(radioFixedKi->isChecked()) + { + bool bKOk = 0; + t_real dKi = editKi->text().toDouble(&bKOk); + if(!bKOk) return; + + tl::t_wavenumber_si ki = dKi / angs; + tl::t_wavenumber_si kf = + tl::my_units_sqrt>(ki*ki - dSign*k_E*k_E); + + t_real dKf = kf*angs; + tl::set_eps_0(dKf, g_dEps); + + std::string strKf = tl::var_to_str(dKf, g_iPrec); + editKf->setText(strKf.c_str()); + } + else + { + bool bKOk = 0; + t_real dKf = editKf->text().toDouble(&bKOk); + if(!bKOk) return; + + tl::t_wavenumber_si kf = dKf / angs; + tl::t_wavenumber_si ki = + tl::my_units_sqrt>(kf*kf + dSign*k_E*k_E); + + t_real dKi = ki*angs; + tl::set_eps_0(dKi, g_dEps); + + std::string strKi = tl::var_to_str(dKi, g_iPrec); + editKi->setText(strKi.c_str()); + } + + CalcMonoAna(); + CalcSample(); +} + +// calc. tas angles -> hkl +void GotoDlg::EditedAngles() +{ + bool bthmOk; + t_real th_m = tl::d2r(edit2ThetaM->text().toDouble(&bthmOk)/2.); + tl::set_eps_0(th_m, g_dEps); + if(bthmOk) + editThetaM->setText(tl::var_to_str(tl::r2d(th_m), g_iPrec).c_str()); + + bool bthaOk; + t_real th_a = tl::d2r(edit2ThetaA->text().toDouble(&bthaOk)/2.); + tl::set_eps_0(th_a, g_dEps); + if(bthaOk) + editThetaA->setText(tl::var_to_str(tl::r2d(th_a), g_iPrec).c_str()); + + bool bthsOk, bttsOk; + t_real th_s = tl::d2r(editThetaS->text().toDouble(&bthsOk)); + t_real tt_s = tl::d2r(edit2ThetaS->text().toDouble(&bttsOk)); + + if(!bthmOk || !bthaOk || !bthsOk || !bttsOk) + return; + + + t_real h,k,l; + t_real dKi, dKf, dE; + ublas::vector vecQ; + bool bFailed = 0; + try + { + tl::get_hkl_from_tas_angles(m_lattice, + m_vec1, m_vec2, + m_dMono, m_dAna, + th_m, th_a, th_s, tt_s, + m_bSenseM, m_bSenseA, m_bSenseS, + &h, &k, &l, + &dKi, &dKf, &dE, 0, + &vecQ); + + if(tl::is_nan_or_inf(h) || tl::is_nan_or_inf(k) || tl::is_nan_or_inf(l)) + throw tl::Err("Invalid hkl."); + } + catch(const std::exception& ex) + { + //log_err(ex.what()); + labelStatus->setText((std::string("Error: ") + ex.what()).c_str()); + bFailed = 1; + } + + const std::wstring strAA = tl::get_spec_char_utf16("AA") + tl::get_spec_char_utf16("sup-") + tl::get_spec_char_utf16("sup1"); + std::wostringstream ostrStatus; + ostrStatus << "Q = " << vecQ << " " << strAA << ", |Q| = " << ublas::norm_2(vecQ) << " " << strAA; + labelQ->setText(QString::fromWCharArray(ostrStatus.str().c_str())); + + if(bFailed) return; + + for(t_real* d : {&h,&k,&l, &dKi,&dKf,&dE}) + tl::set_eps_0(*d, g_dEps); + + editH->setText(tl::var_to_str(h, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k, g_iPrec).c_str()); + editL->setText(tl::var_to_str(l, g_iPrec).c_str()); + + editKi->setText(tl::var_to_str(dKi, g_iPrec).c_str()); + editKf->setText(tl::var_to_str(dKf, g_iPrec).c_str()); + editE->setText(tl::var_to_str(dE, g_iPrec).c_str()); + + m_dMono2Theta = th_m*2.; + m_dAna2Theta = th_a*2.; + m_dSample2Theta = tt_s; + m_dSampleTheta = th_s; + m_bMonoAnaOk = 1; + m_bSampleOk = 1; + + if(m_bMonoAnaOk && m_bSampleOk) + labelStatus->setText("Position OK."); +} + +void GotoDlg::GetCurPos() +{ + if(!m_bHasParamsRecip) + return; + + tl::set_eps_0(m_paramsRecip.dki, g_dEps); + tl::set_eps_0(m_paramsRecip.dkf, g_dEps); + tl::set_eps_0(m_paramsRecip.Q_rlu[0], g_dEps); + tl::set_eps_0(m_paramsRecip.Q_rlu[1], g_dEps); + tl::set_eps_0(m_paramsRecip.Q_rlu[2], g_dEps); + + editKi->setText(tl::var_to_str(m_paramsRecip.dki, g_iPrec).c_str()); + editKf->setText(tl::var_to_str(m_paramsRecip.dkf, g_iPrec).c_str()); + + editH->setText(tl::var_to_str(-m_paramsRecip.Q_rlu[0], g_iPrec).c_str()); + editK->setText(tl::var_to_str(-m_paramsRecip.Q_rlu[1], g_iPrec).c_str()); + editL->setText(tl::var_to_str(-m_paramsRecip.Q_rlu[2], g_iPrec).c_str()); + + EditedKiKf(); + CalcMonoAna(); + CalcSample(); +} + +void GotoDlg::RecipParamsChanged(const RecipParams& params) +{ + m_bHasParamsRecip = 1; + m_paramsRecip = params; +} + +void GotoDlg::ButtonBoxClicked(QAbstractButton* pBtn) +{ + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ApplyRole || + buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + ApplyCurPos(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::RejectRole) + { + reject(); + } + + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + if(m_pSettings) + { + m_pSettings->setValue("goto_pos/geo", saveGeometry()); + m_pSettings->setValue("goto_pos/ki_fix", radioFixedKi->isChecked()); + } + + QDialog::accept(); + } +} + +void GotoDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +//------------------------------------------------------------------------------ + +struct HklPos +{ + t_real dh, dk, dl; + t_real dki, dkf; + t_real dE; +}; + +bool GotoDlg::ApplyCurPos() +{ + if(!m_bMonoAnaOk || !m_bSampleOk) + return false; + + CrystalOptions crys; + TriangleOptions triag; + + triag.bChangedMonoTwoTheta = 1; + triag.dMonoTwoTheta = this->m_dMono2Theta; + + triag.bChangedAnaTwoTheta = 1; + triag.dAnaTwoTheta = this->m_dAna2Theta; + + triag.bChangedTheta = 1; + triag.dTheta = this->m_dSampleTheta; + + triag.bChangedAngleKiVec0 = 1; + + t_real dSampleTheta = m_dSampleTheta; + if(!m_bSenseS) dSampleTheta = -dSampleTheta; + triag.dAngleKiVec0 = tl::get_pi()/2. - dSampleTheta; + //log_info("kivec0 = ", triag.dAngleKiVec0/M_PI*180.); + //log_info("th = ", m_dSampleTheta/M_PI*180.); + + triag.bChangedTwoTheta = 1; + triag.dTwoTheta = this->m_dSample2Theta; + // TODO: correct hack in taz.cpp + if(!m_bSenseS) triag.dTwoTheta = -triag.dTwoTheta; + + emit vars_changed(crys, triag); + return true; +} + +bool GotoDlg::GotoPos(QListWidgetItem* pItem, bool bApply) +{ + if(!pItem) return false; + HklPos* pPos = (HklPos*)pItem->data(Qt::UserRole).value(); + if(!pPos) return false; + + editH->setText(tl::var_to_str(pPos->dh, g_iPrec).c_str()); + editK->setText(tl::var_to_str(pPos->dk, g_iPrec).c_str()); + editL->setText(tl::var_to_str(pPos->dl, g_iPrec).c_str()); + editKi->setText(tl::var_to_str(pPos->dki, g_iPrec).c_str()); + editKf->setText(tl::var_to_str(pPos->dkf, g_iPrec).c_str()); + + EditedKiKf(); + CalcSample(); + + if(bApply) + return ApplyCurPos(); + return m_bMonoAnaOk && m_bSampleOk; +} + +bool GotoDlg::GotoPos(unsigned int iItem) +{ + if(int(iItem) >= listSeq->count()) + return false; + return GotoPos(listSeq->item(int(iItem)), 1); +} + +void GotoDlg::ListItemSelected() +{ + QListWidgetItem *pItem = listSeq->currentItem(); + GotoPos(pItem, 0); +} + +void GotoDlg::ListItemDoubleClicked(QListWidgetItem* pItem) +{ + bool bOk = GotoPos(pItem, 1); + if(!bOk) + QMessageBox::critical(this, "Error", "Invalid position."); +} + +void GotoDlg::AddPosToList(t_real dh, t_real dk, t_real dl, t_real dki, t_real dkf) +{ + HklPos *pPos = new HklPos; + + pPos->dh = dh; + pPos->dk = dk; + pPos->dl = dl; + pPos->dki = dki; + pPos->dkf = dkf; + pPos->dE = (tl::k2E(pPos->dki/angs) - tl::k2E(pPos->dkf/angs))/tl::meV; + + tl::set_eps_0(pPos->dh, g_dEps); + tl::set_eps_0(pPos->dk, g_dEps); + tl::set_eps_0(pPos->dl, g_dEps); + tl::set_eps_0(pPos->dki, g_dEps); + tl::set_eps_0(pPos->dkf, g_dEps); + tl::set_eps_0(pPos->dE, g_dEps); + + const std::wstring strAA = tl::get_spec_char_utf16("AA") + tl::get_spec_char_utf16("sup-") + tl::get_spec_char_utf16("sup1"); + + std::wostringstream ostrHKL; + ostrHKL.precision(4); + ostrHKL << "(" << pPos->dh << ", " << pPos->dk << ", " << pPos->dl << ") rlu\n"; + ostrHKL << "ki = " << pPos->dki << " " << strAA; + ostrHKL << ", kf = " << pPos->dkf << " " << strAA << "\n"; + ostrHKL << "E = " << pPos->dE << " meV"; + + QString qstr = QString::fromWCharArray(ostrHKL.str().c_str()); + QListWidgetItem* pItem = new QListWidgetItem(qstr, listSeq); + pItem->setData(Qt::UserRole, QVariant::fromValue(pPos)); +} + +void GotoDlg::AddPosToList() +{ + t_real dh = tl::str_to_var(editH->text().toStdString()); + t_real dk = tl::str_to_var(editK->text().toStdString()); + t_real dl = tl::str_to_var(editL->text().toStdString()); + t_real dki = tl::str_to_var(editKi->text().toStdString()); + t_real dkf = tl::str_to_var(editKf->text().toStdString()); + + AddPosToList(dh, dk, dl, dki, dkf); +} + +void GotoDlg::RemPosFromList() +{ + QListWidgetItem *pItem = listSeq->currentItem(); + if(pItem) + { + HklPos* pPos = (HklPos*)pItem->data(Qt::UserRole).value(); + if(pPos) delete pPos; + delete pItem; + } +} + +void GotoDlg::ClearList() +{ + while(listSeq->count()) + { + QListWidgetItem *pItem = listSeq->item(0); + if(!pItem) break; + + HklPos* pPos = (HklPos*)pItem->data(Qt::UserRole).value(); + if(pPos) delete pPos; + delete pItem; + } +} + + +void GotoDlg::LoadList() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + strDirLast = m_pSettings->value("goto_pos/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getOpenFileName(this, + "Load Positions", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + if(qstrFile == "") + return; + + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load positions."); + return; + } + + Load(xml, strXmlRoot); + if(m_pSettings) + m_pSettings->setValue("goto_pos/last_dir", QString(strDir.c_str())); +} + +void GotoDlg::SaveList() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + m_pSettings->value("goto_pos/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getSaveFileName(this, + "Save Positions", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + + if(qstrFile == "") + return; + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + std::map mapConf; + Save(mapConf, strXmlRoot); + + tl::Prop xml; + xml.Add(mapConf); + bool bOk = xml.Save(strFile.c_str(), tl::PropType::XML); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not save positions."); + + if(bOk && m_pSettings) + m_pSettings->setValue("goto_pos/last_dir", QString(strDir.c_str())); +} + +void GotoDlg::Save(std::map& mapConf, const std::string& strXmlRoot) +{ + mapConf[strXmlRoot + "goto_pos/h"] = editH->text().toStdString(); + mapConf[strXmlRoot + "goto_pos/k"] = editK->text().toStdString(); + mapConf[strXmlRoot + "goto_pos/l"] = editL->text().toStdString(); + mapConf[strXmlRoot + "goto_pos/ki"] = editKi->text().toStdString(); + mapConf[strXmlRoot + "goto_pos/kf"] = editKf->text().toStdString(); + mapConf[strXmlRoot + "goto_pos/cki"] = radioFixedKi->isChecked()?"1":"0"; + + // favlist + for(int iItem=0; iItemcount(); ++iItem) + { + const QListWidgetItem *pItem = listSeq->item(iItem); + if(!pItem) continue; + const HklPos* pPos = (HklPos*)pItem->data(Qt::UserRole).value(); + if(!pPos) continue; + + std::ostringstream ostrItemBase; + ostrItemBase << "goto_favlist/pos_" << iItem << "/"; + std::string strItemBase = ostrItemBase.str(); + + mapConf[strXmlRoot + strItemBase + "h"] = tl::var_to_str(pPos->dh); + mapConf[strXmlRoot + strItemBase + "k"] = tl::var_to_str(pPos->dk); + mapConf[strXmlRoot + strItemBase + "l"] = tl::var_to_str(pPos->dl); + mapConf[strXmlRoot + strItemBase + "ki"] = tl::var_to_str(pPos->dki); + mapConf[strXmlRoot + strItemBase + "kf"] = tl::var_to_str(pPos->dkf); + } +} + +void GotoDlg::Load(tl::Prop& xml, const std::string& strXmlRoot) +{ + bool bOk=0; + + editH->setText(tl::var_to_str(xml.Query((strXmlRoot + "goto_pos/h").c_str(), 1., &bOk), g_iPrec).c_str()); + editK->setText(tl::var_to_str(xml.Query((strXmlRoot + "goto_pos/k").c_str(), 0., &bOk), g_iPrec).c_str()); + editL->setText(tl::var_to_str(xml.Query((strXmlRoot + "goto_pos/l").c_str(), 0., &bOk), g_iPrec).c_str()); + editKi->setText(tl::var_to_str(xml.Query((strXmlRoot + "goto_pos/ki").c_str(), 1.4, &bOk), g_iPrec).c_str()); + editKf->setText(tl::var_to_str(xml.Query((strXmlRoot + "goto_pos/kf").c_str(), 1.4, &bOk), g_iPrec).c_str()); + radioFixedKi->setChecked(xml.Query((strXmlRoot + "goto_pos/cki").c_str(), 0, &bOk)); + + // favlist + ClearList(); + unsigned int iItem=0; + while(1) + { + std::ostringstream ostrItemBase; + ostrItemBase << "goto_favlist/pos_" << iItem << "/"; + std::string strItemBase = ostrItemBase.str(); + + if(!xml.Exists((strXmlRoot + strItemBase).c_str())) + break; + + t_real dh = xml.Query((strXmlRoot + strItemBase + "h").c_str(), 0., &bOk); + t_real dk = xml.Query((strXmlRoot + strItemBase + "k").c_str(), 0., &bOk); + t_real dl = xml.Query((strXmlRoot + strItemBase + "l").c_str(), 0., &bOk); + t_real dki = xml.Query((strXmlRoot + strItemBase + "ki").c_str(), 0., &bOk); + t_real dkf = xml.Query((strXmlRoot + strItemBase + "kf").c_str(), 0., &bOk); + + AddPosToList(dh, dk, dl, dki, dkf); + ++iItem; + } + + EditedKiKf(); + CalcSample(); +} + + +#include "GotoDlg.moc" diff --git a/dialogs/GotoDlg.h b/dialogs/GotoDlg.h new file mode 100644 index 0000000..3f73373 --- /dev/null +++ b/dialogs/GotoDlg.h @@ -0,0 +1,110 @@ +/* + * Goto Dialog + * @author Tobias Weber + * @date 15-oct-2014 + * @license GPLv2 + */ + +#ifndef __GOTO_DLG_H__ +#define __GOTO_DLG_H__ + +#include +#include +#include "ui/ui_goto.h" + +#include "tlibs/math/lattice.h" +#include "tlibs/math/linalg.h" +#include "tlibs/file/prop.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "tools/taz/tasoptions.h" +#include "RecipParamDlg.h" + + +class GotoDlg : public QDialog, Ui::GotoDlg +{ Q_OBJECT + private: + bool m_bMonoAnaOk = 0; + bool m_bSampleOk = 0; + + public: + GotoDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~GotoDlg(); + + protected: + QSettings *m_pSettings = 0; + + ublas::vector m_vec1, m_vec2; + tl::Lattice m_lattice; + RecipParams m_paramsRecip; + bool m_bHasParamsRecip = 0; + + t_real_glob m_dMono2Theta; + t_real_glob m_dSample2Theta; + t_real_glob m_dSampleTheta; + t_real_glob m_dAna2Theta; + + t_real_glob m_dAna = 3.355; + t_real_glob m_dMono = 3.355; + + bool m_bSenseM=0, m_bSenseS=1, m_bSenseA=0; + + public: + void ClearList(); + + protected: + bool GotoPos(QListWidgetItem* pItem, bool bApply); + bool ApplyCurPos(); + + protected slots: + void EditedKiKf(); + void EditedE(); + void EditedAngles(); + void GetCurPos(); + + // list + void AddPosToList(); + void RemPosFromList(); + void LoadList(); + void SaveList(); + void ListItemSelected(); + void ListItemDoubleClicked(QListWidgetItem*); + + public slots: + void CalcMonoAna(); + void CalcSample(); + + void AddPosToList(t_real_glob dh, t_real_glob dk, t_real_glob dl, t_real_glob dki, t_real_glob dkf); + + public: + void SetLattice(const tl::Lattice& lattice) { m_lattice = lattice; } + void SetScatteringPlane(const ublas::vector& vec1, const ublas::vector& vec2) + { m_vec1 = vec1; m_vec2 = vec2; } + + void SetD(t_real_glob dMono, t_real_glob dAna) { m_dMono = dMono; m_dAna = dAna; } + void SetSenses(bool bM, bool bS, bool bA) + { m_bSenseM=bM; m_bSenseS=bS; m_bSenseA=bA; } + + void SetMonoSense(bool bSense) { m_bSenseM = bSense; } + void SetSampleSense(bool bSense) { m_bSenseS = bSense; } + void SetAnaSense(bool bSense) { m_bSenseA = bSense; } + + bool GotoPos(unsigned int iItem); + + protected slots: + void ButtonBoxClicked(QAbstractButton* pBtn); + public slots: + void RecipParamsChanged(const RecipParams&); + + signals: + void vars_changed(const CrystalOptions& crys, const TriangleOptions& triag); + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + + public: + void Save(std::map& mapConf, const std::string& strXmlRoot); + void Load(tl::Prop& xml, const std::string& strXmlRoot); +}; + +#endif diff --git a/dialogs/NetCacheDlg.cpp b/dialogs/NetCacheDlg.cpp new file mode 100644 index 0000000..46d20e2 --- /dev/null +++ b/dialogs/NetCacheDlg.cpp @@ -0,0 +1,204 @@ +/* + * Cache dialog + * @author Tobias Weber + * @date 21-oct-2014 + * @license GPLv2 + */ + +#include "NetCacheDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/helper/flags.h" +#include "tlibs/log/log.h" +#include "libs/qthelper.h" +#include +#include + +using t_real = t_real_glob; + +enum +{ + ITEM_KEY = 0, + ITEM_VALUE = 1, + ITEM_TIMESTAMP = 2, + ITEM_AGE = 3 +}; + +NetCacheDlg::NetCacheDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + tableCache->setColumnCount(4); + tableCache->setRowCount(0); + tableCache->setColumnWidth(ITEM_KEY, 200); + tableCache->setColumnWidth(ITEM_VALUE, 200); + tableCache->setColumnWidth(ITEM_TIMESTAMP, 140); + tableCache->setColumnWidth(ITEM_AGE, 140); + tableCache->verticalHeader()->setDefaultSectionSize(tableCache->verticalHeader()->minimumSectionSize()+2); + + tableCache->setHorizontalHeaderItem(ITEM_KEY, new QTableWidgetItem("Name")); + tableCache->setHorizontalHeaderItem(ITEM_VALUE, new QTableWidgetItem("Value")); + tableCache->setHorizontalHeaderItem(ITEM_TIMESTAMP, new QTableWidgetItem("Time Stamp")); + tableCache->setHorizontalHeaderItem(ITEM_AGE, new QTableWidgetItem("Age")); + +#if QT_VER >= 5 + QObject::connect(&m_timer, &QTimer::timeout, this, &NetCacheDlg::UpdateTimer); +#else + QObject::connect(&m_timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); +#endif + m_timer.start(s_iTimer); + + + if(m_pSettings && m_pSettings->contains("net_cache/geo")) + restoreGeometry(m_pSettings->value("net_cache/geo").toByteArray()); +} + +NetCacheDlg::~NetCacheDlg() +{} + +void NetCacheDlg::UpdateTimer() +{ + UpdateAge(-1); +} + +void NetCacheDlg::hideEvent(QHideEvent *pEvt) +{ + m_timer.stop(); +} + +void NetCacheDlg::showEvent(QShowEvent *pEvt) +{ + m_timer.start(s_iTimer); +} + +void NetCacheDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("net_cache/geo", saveGeometry()); + + QDialog::accept(); +} + +void NetCacheDlg::UpdateValue(const std::string& strKey, const CacheVal& val) +{ + const bool bSortTable = tableCache->isSortingEnabled(); + tableCache->setSortingEnabled(0); + + int iRow = 0; + QTableWidgetItem *pItem = 0; + QString qstrKey = strKey.c_str(); + QString qstrVal = val.strVal.c_str(); + //tl::log_debug("updating net cache: ", strKey, ", ", val.strVal); + + for(iRow=0; iRow < tableCache->rowCount(); ++iRow) + { + if(tableCache->item(iRow, 0)->text() == qstrKey) + { + pItem = tableCache->item(iRow, 0); + break; + } + } + + if(pItem) // update items + { + tableCache->item(iRow, 1)->setText(qstrVal); + dynamic_cast*>(tableCache->item(iRow, ITEM_TIMESTAMP))-> + SetValue(val.dTimestamp); + dynamic_cast*>(tableCache->item(iRow, ITEM_AGE))-> + SetValueKeepText(val.dTimestamp); + } + else // insert new items + { + iRow = tableCache->rowCount(); + tableCache->setRowCount(iRow+1); + tableCache->setItem(iRow, ITEM_KEY, new QTableWidgetItem(qstrKey)); + tableCache->setItem(iRow, ITEM_VALUE, new QTableWidgetItem(qstrVal)); + tableCache->setItem(iRow, ITEM_TIMESTAMP, new QTableWidgetItemWrapper(val.dTimestamp)); + tableCache->setItem(iRow, ITEM_AGE, new QTableWidgetItemWrapper(val.dTimestamp, "")); + } + + UpdateAge(iRow); + tableCache->setSortingEnabled(bSortTable); +} + +void NetCacheDlg::UpdateAll(const t_mapCacheVal& map) +{ + for(const t_mapCacheVal::value_type& pair : map) + { + const std::string& strKey = pair.first; + const CacheVal& val = pair.second; + + UpdateValue(strKey, val); + } +} + +void NetCacheDlg::UpdateAge(int iRow) +{ + const bool bSortTable = tableCache->isSortingEnabled(); + tableCache->setSortingEnabled(0); + + // update all + if(iRow<0) + { + for(int iCurRow=0; iCurRowrowCount(); ++iCurRow) + UpdateAge(iCurRow); + + return; + } + + QTableWidgetItemWrapper* pItemTimestamp = + dynamic_cast*>(tableCache->item(iRow, ITEM_TIMESTAMP)); + QTableWidgetItem *pItem = tableCache->item(iRow, ITEM_AGE); + if(!pItemTimestamp || !pItem) return; + + t_real dTimestamp = pItemTimestamp->GetValue(); + t_real dNow = std::chrono::system_clock::now().time_since_epoch().count(); + dNow *= t_real(std::chrono::system_clock::period::num) / t_real(std::chrono::system_clock::period::den); + t_real dAgeS = dNow - dTimestamp; + //std::cout << strKey << " = " << val.strVal << " (age: " << dAge << "s)" << std::endl; + + int iAgeS = int(dAgeS); + int iAgeM = 0; + int iAgeH = 0; + int iAgeD = 0; + + if(iAgeS > 60) + { + iAgeM = iAgeS / 60; + iAgeS = iAgeS % 60; + } + if(iAgeM > 60) + { + iAgeH = iAgeM / 60; + iAgeM = iAgeM % 60; + } + if(iAgeH > 24) + { + iAgeD = iAgeH / 24; + iAgeH = iAgeH % 24; + } + + bool bHadPrev = 0; + std::string strAge; + if(iAgeD || bHadPrev) { strAge += tl::var_to_str(iAgeD) + "d "; bHadPrev = 1; } + if(iAgeH || bHadPrev) { strAge += tl::var_to_str(iAgeH) + "h "; bHadPrev = 1; } + if(iAgeM || bHadPrev) { strAge += tl::var_to_str(iAgeM) + "m "; bHadPrev = 1; } + /*if(iAgeS || bHadPrev)*/ { strAge += tl::var_to_str(iAgeS) + "s "; bHadPrev = 1; } + pItem->setText(strAge.c_str()); + + tableCache->setSortingEnabled(bSortTable); +} + +void NetCacheDlg::ClearAll() +{ + tableCache->clearContents(); + tableCache->setRowCount(0); +} + +#include "NetCacheDlg.moc" diff --git a/dialogs/NetCacheDlg.h b/dialogs/NetCacheDlg.h new file mode 100644 index 0000000..5d9430d --- /dev/null +++ b/dialogs/NetCacheDlg.h @@ -0,0 +1,56 @@ +/* + * Cache dialog + * @author Tobias Weber + * @date 21-oct-2014 + * @license GPLv2 + */ + +#ifndef __NET_CACHE_DLG_H__ +#define __NET_CACHE_DLG_H__ + +#include +#include +#include +#include +#include "ui/ui_netcache.h" +#include "libs/globals.h" + + +struct CacheVal +{ + std::string strVal; + t_real_glob dTimestamp; +}; + +typedef std::map t_mapCacheVal; + + +class NetCacheDlg : public QDialog, Ui::NetCacheDlg +{ Q_OBJECT +protected: + QSettings *m_pSettings = 0; + + static const int s_iTimer = 1000; + QTimer m_timer; + +protected: + virtual void hideEvent(QHideEvent *pEvt) override; + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + + void UpdateAge(int iRow=-1); + +public: + NetCacheDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~NetCacheDlg(); + +protected slots: + void UpdateTimer(); + +public slots: + void ClearAll(); + void UpdateValue(const std::string& strKey, const CacheVal& val); + void UpdateAll(const t_mapCacheVal& map); +}; + +#endif diff --git a/dialogs/NeutronDlg.cpp b/dialogs/NeutronDlg.cpp new file mode 100644 index 0000000..27cf100 --- /dev/null +++ b/dialogs/NeutronDlg.cpp @@ -0,0 +1,750 @@ +/** + * Neutron Properties Dialog + * @author Tobias Weber + * @date jul-2013, 28-may-2014 + * @license GPLv2 + */ + +#include "NeutronDlg.h" +#include + +#include "tlibs/string/string.h" +#include "tlibs/string/eval.h" +#include "tlibs/math/math.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/helper/misc.h" +#include "libs/globals.h" + +#include +#include +#include +#include + +using t_real = t_real_glob; +namespace co = boost::units::si::constants::codata; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_angle_si rads = tl::get_one_radian(); +static const tl::t_temperature_si kelvin = tl::get_one_kelvin(); +static const tl::t_time_si ps = tl::get_one_picosecond(); +static const tl::t_time_si sec = tl::get_one_second(); +static const tl::t_length_si meter = tl::get_one_meter(); +static const tl::t_flux_si tesla = tl::get_one_tesla(); +static const tl::t_flux_si millitesla = tesla*t_real(1e-3); +static const tl::t_flux_si kilogauss = tl::get_one_kilogauss(); + + +NeutronDlg::NeutronDlg(QWidget* pParent, QSettings *pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + setupConstants(); + + QObject::connect(editLam, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronLam())); + QObject::connect(editE, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronE())); + QObject::connect(editOm, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronOm())); + QObject::connect(editF, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronF())); + QObject::connect(editV, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronv())); + QObject::connect(editK, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronk())); + QObject::connect(editT, SIGNAL(textEdited(const QString&)), this, SLOT(CalcNeutronT())); + + CalcNeutronLam(); + + + + std::vector editsDir = {editBraggDirN, editBraggDirLam, editBraggDirD, editBraggDirT, editBraggDirTT}; + std::vector editsReci = {editBraggReciN, editBraggReciLam, editBraggReciQ, editBraggReciT, editBraggReciTT}; + std::vector radioDir = {/*radioBraggDirN,*/ radioBraggDirLam, radioBraggDirD, radioBraggDirTT}; + std::vector radioReci = {/*radioBraggReciN,*/ radioBraggReciLam, radioBraggReciQ, radioBraggReciTT}; + + QObject::connect(editBraggDirT, SIGNAL(textEdited(const QString&)), this, SLOT(RealThetaEdited())); + QObject::connect(editBraggReciT, SIGNAL(textEdited(const QString&)), this, SLOT(RecipThetaEdited())); + QObject::connect(editBraggDirTT, SIGNAL(textEdited(const QString&)), this, SLOT(RealTwoThetaEdited())); + QObject::connect(editBraggReciTT, SIGNAL(textEdited(const QString&)), this, SLOT(RecipTwoThetaEdited())); + + for(QLineEdit* pEdit : editsDir) + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcBraggReal())); + for(QLineEdit* pEdit : editsReci) + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcBraggRecip())); + for(QRadioButton* pRadio : radioDir) + { + QObject::connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(EnableRealEdits())); + QObject::connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(CalcBraggReal())); + } + for(QRadioButton* pRadio : radioReci) + { + QObject::connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(EnableRecipEdits())); + QObject::connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(CalcBraggRecip())); + } + QObject::connect(editEval, SIGNAL(textEdited(const QString&)), this, SLOT(Eval(const QString&))); + + + EnableRealEdits(); + EnableRecipEdits(); + CalcBraggReal(); + CalcBraggRecip(); + + + if(m_pSettings) + { + if(m_pSettings->contains("neutron_props/geo")) + restoreGeometry(m_pSettings->value("neutron_props/geo").toByteArray()); + + bool bOk = 0; + t_real dLam = m_pSettings->value("neutron_props/lam").toDouble(&bOk); + if(!bOk) + dLam = 5.; + + std::string strLam = tl::var_to_str(dLam, g_iPrec); + editLam->setText(strLam.c_str()); + + CalcNeutronLam(); + } +} + +NeutronDlg::~NeutronDlg() +{} + + +// ----------------------------------------------------------------------------- + + +void NeutronDlg::CalcNeutronLam() +{ + std::string strInput = editLam->text().toStdString(); + + tl::t_length_si lam_n = tl::str_to_var(strInput) * angs; + + tl::t_wavenumber_si k_n = tl::lam2k(lam_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + tl::t_energy_si E_n = p_n*p_n / (t_real(2.)*tl::get_m_n()); + + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronk() +{ + std::string strInput = editK->text().toStdString(); + + tl::t_wavenumber_si k_n = tl::str_to_var(strInput) / angs; + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + tl::t_energy_si E_n = p_n*p_n / (t_real(2.)*tl::get_m_n()); + + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronv() +{ + std::string strInput = editV->text().toStdString(); + + tl::t_velocity_si v_n = tl::str_to_var(strInput) * meter / sec; + tl::t_wavenumber_si k_n = tl::v2k(v_n); + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + tl::t_energy_si E_n = p_n*p_n / (t_real(2.)*tl::get_m_n()); + + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronE() +{ + std::string strInput = editE->text().toStdString(); + + bool bImag = 0; + tl::t_energy_si E_n = tl::str_to_var(strInput) * meV; + tl::t_wavenumber_si k_n = tl::E2k(E_n, bImag); + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronOm() +{ + std::string strInput = editOm->text().toStdString(); + + bool bImag = 0; + tl::t_energy_si E_n = tl::str_to_var(strInput) / ps * tl::get_hbar(); + tl::t_wavenumber_si k_n = tl::E2k(E_n, bImag); + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronF() +{ + std::string strInput = editF->text().toStdString(); + + bool bImag = 0; + tl::t_energy_si E_n = tl::str_to_var(strInput) / ps * tl::get_h(); + tl::t_wavenumber_si k_n = tl::E2k(E_n, bImag); + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editT->setText(tl::var_to_str((E_n / tl::get_kB()) / kelvin, g_iPrec).c_str()); +} + +void NeutronDlg::CalcNeutronT() +{ + std::string strInput = editT->text().toStdString(); + + bool bImag; + tl::t_temperature_si T_n = tl::str_to_var(strInput) * kelvin; + tl::t_energy_si E_n = T_n * tl::get_kB(); + tl::t_wavenumber_si k_n = tl::E2k(E_n, bImag); + tl::t_length_si lam_n = tl::k2lam(k_n); + tl::t_momentum_si p_n = tl::lam2p(lam_n); + + editLam->setText(tl::var_to_str(lam_n / angs, g_iPrec).c_str()); + editK->setText(tl::var_to_str(k_n * angs, g_iPrec).c_str()); + editV->setText(tl::var_to_str((p_n / tl::get_m_n()) * sec / meter, g_iPrec).c_str()); + editE->setText(tl::var_to_str(E_n / meV, g_iPrec).c_str()); + editOm->setText(tl::var_to_str(E_n / tl::get_hbar() * ps, g_iPrec).c_str()); + editF->setText(tl::var_to_str(E_n / tl::get_h() * ps, g_iPrec).c_str()); +} + + +// ----------------------------------------------------------------------------- + + +void NeutronDlg::setupConstants() +{ + // ------------------------------------------------------------------------- + // constants + struct Constant + { + std::string strSymbol; + std::string strName; + + std::string strVal; + }; + + std::vector vecConsts; + + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::one_eV; + + Constant constant; + constant.strSymbol = "eV"; + constant.strName = "1 electron volt"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_h(); + + Constant constant; + constant.strSymbol = "h"; + constant.strName = "Planck constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << (tl::get_h() / tl::one_eV) << " eV"; + + Constant constant; + constant.strSymbol = "h"; + constant.strName = "Planck constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_hbar(); + + Constant constant; + constant.strSymbol = "hbar"; + constant.strName = "Planck constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << (tl::get_hbar() / tl::one_eV) << " eV"; + + Constant constant; + constant.strSymbol = "hbar"; + constant.strName = "Planck constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_m_n(); + + Constant constant; + constant.strSymbol = "m_n"; + constant.strName = "Neutron mass"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_g_n(); + + Constant constant; + constant.strSymbol = "g_n"; + constant.strName = "Neutron g"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << co::gamma_n; // TODO: replace with a tl::... getter + + Constant constant; + constant.strSymbol = "gamma_n"; + constant.strName = "Neutron gyromagnetic ratio"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + //ostrVal << tl::get_mu_n(); + ostrVal << t_real(tl::get_mu_n() / meV * tesla) << " meV/T"; + + Constant constant; + constant.strSymbol = "mu_n"; + constant.strName = "Neutron magnetic moment"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + //ostrVal << co::mu_N; + ostrVal << t_real(tl::get_mu_N() / meV * tesla) << " meV/T"; + + Constant constant; + constant.strSymbol = "mu_N"; + constant.strName = "Nuclear magneton"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << t_real(tl::get_muB() / meV * tesla) << " meV/T"; + + Constant constant; + constant.strSymbol = "mu_B"; + constant.strName = "Bohr magneton"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + //ostrVal << std::scientific; + ostrVal << t_real(-tl::get_g_e() * tl::get_muB() / meV * tesla) << " meV/T"; + + Constant constant; + constant.strSymbol = "-g_e * mu_B"; + constant.strName = "Zeeman shift"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_c(); + + Constant constant; + constant.strSymbol = "c"; + constant.strName = "Vacuum speed of light"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << tl::get_kB(); + + Constant constant; + constant.strSymbol = "k_B"; + constant.strName = "Boltzmann constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + { + std::ostringstream ostrVal; + ostrVal << std::scientific; + ostrVal << t_real(tl::get_kB() / meV * kelvin) << " meV/K"; + + Constant constant; + constant.strSymbol = "k_B"; + constant.strName = "Boltzmann constant"; + constant.strVal = tl::insert_before(ostrVal.str(), "(", "\n"); + + vecConsts.push_back(std::move(constant)); + } + // ------------------------------------------------------------------------- + + + + // ------------------------------------------------------------------------- + // conversions + struct Conversion + { + std::string strName; + std::string strVal; + }; + + std::vector vecConvs; + + { + Conversion conv; + conv.strName = "k^2 in A^(-2) -> E in meV"; + conv.strVal = tl::var_to_str(tl::get_KSQ2E(), g_iPrec) + + " meV per A^(-2)"; + + vecConvs.emplace_back(std::move(conv)); + } + { + Conversion conv; + conv.strName = "E in meV -> k^2 in A^(-2)"; + conv.strVal = tl::var_to_str(tl::get_E2KSQ(), g_iPrec) + + " A^(-2) per meV"; + + vecConvs.emplace_back(std::move(conv)); + } + + { + t_real tConv = meV / tl::get_h() * ps; + + Conversion conv; + conv.strName = "E in meV -> f in THz"; + conv.strVal = tl::var_to_str(tConv, g_iPrec) + " THz per meV"; + + vecConvs.emplace_back(std::move(conv)); + } + { + t_real tConv = t_real(1)/(meV / tl::get_h() * ps); + + Conversion conv; + conv.strName = "f in THz -> E in meV"; + conv.strVal = tl::var_to_str(tConv, g_iPrec) + " meV per THz"; + + vecConvs.emplace_back(std::move(conv)); + } + + { + Conversion conv; + conv.strName = "B in kG -> B in mT"; + conv.strVal = tl::var_to_str(t_real(kilogauss/millitesla), g_iPrec) + " mT per kG"; + + vecConvs.emplace_back(std::move(conv)); + } + { + Conversion conv; + conv.strName = "B in mT -> B in kG"; + conv.strVal = tl::var_to_str(t_real(millitesla/kilogauss), g_iPrec) + " kG per mT"; + + vecConvs.emplace_back(std::move(conv)); + } + // ------------------------------------------------------------------------- + + + + // ------------------------------------------------------------------------- + // constants table + const bool bSortConst = tableConst->isSortingEnabled(); + tableConst->setSortingEnabled(0); + + tableConst->setColumnCount(3); + tableConst->setRowCount(vecConsts.size()); + tableConst->setColumnWidth(2, 200); + //tableConst->verticalHeader()->setDefaultSectionSize(tableConst->verticalHeader()->minimumSectionSize()+2); + + for(unsigned int iConst=0; iConstsetText(constant.strSymbol.c_str()); + tableConst->setItem(iConst,0,pConstSym); + + QTableWidgetItem *pConstName = new QTableWidgetItem(); + pConstName->setText(constant.strName.c_str()); + tableConst->setItem(iConst,1,pConstName); + + QTableWidgetItem *pConstVal = new QTableWidgetItem(); + pConstVal->setText(constant.strVal.c_str()); + tableConst->setItem(iConst,2,pConstVal); + + pConstName->setFlags(pConstName->flags() & ~Qt::ItemIsEditable); + //pConstVal->setFlags(pConstVal->flags() & ~Qt::ItemIsEditable); + } + + tableConst->setSortingEnabled(bSortConst); + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + // conversion table + const bool bSortConv = tableConv->isSortingEnabled(); + tableConv->setSortingEnabled(0); + + tableConv->setColumnCount(2); + tableConv->setRowCount(vecConvs.size()); + tableConv->setColumnWidth(0, 200); + tableConv->setColumnWidth(1, 200); + //tableConv->verticalHeader()->setDefaultSectionSize(tableConv->verticalHeader()->minimumSectionSize()+2); + + for(unsigned int iConst=0; iConstsetText(conv.strName.c_str()); + tableConv->setItem(iConst, 0, pConstName); + + QTableWidgetItem *pConstVal = new QTableWidgetItem(); + pConstVal->setText(conv.strVal.c_str()); + tableConv->setItem(iConst, 1, pConstVal); + + pConstName->setFlags(pConstName->flags() & ~Qt::ItemIsEditable); + //pConstVal->setFlags(pConstVal->flags() & ~Qt::ItemIsEditable); + } + + tableConv->setSortingEnabled(bSortConv); + // ------------------------------------------------------------------------- +} + + +// ----------------------------------------------------------------------------- + +void NeutronDlg::EnableRealEdits() +{ + //void (QLineEdit::*pFunc)(bool) = &QLineEdit::setDisabled; + void (QLineEdit::*pFunc)(bool) = &QLineEdit::setReadOnly; + + (editBraggDirLam->*pFunc)(0); + (editBraggDirD->*pFunc)(0); + (editBraggDirT->*pFunc)(0); + (editBraggDirTT->*pFunc)(0); + + if(radioBraggDirLam->isChecked()) + (editBraggDirLam->*pFunc)(1); + else if(radioBraggDirD->isChecked()) + (editBraggDirD->*pFunc)(1); + else if(radioBraggDirTT->isChecked()) + { + (editBraggDirT->*pFunc)(1); + (editBraggDirTT->*pFunc)(1); + } +} + +void NeutronDlg::EnableRecipEdits() +{ + //void (QLineEdit::*pFunc)(bool) = &QLineEdit::setDisabled; + void (QLineEdit::*pFunc)(bool) = &QLineEdit::setReadOnly; + + (editBraggReciLam->*pFunc)(0); + (editBraggReciQ->*pFunc)(0); + (editBraggReciT->*pFunc)(0); + (editBraggReciTT->*pFunc)(0); + + if(radioBraggReciLam->isChecked()) + (editBraggReciLam->*pFunc)(1); + else if(radioBraggReciQ->isChecked()) + (editBraggReciQ->*pFunc)(1); + else if(radioBraggReciTT->isChecked()) + { + (editBraggReciT->*pFunc)(1); + (editBraggReciTT->*pFunc)(1); + } +} + + +void NeutronDlg::SetEditTT(QLineEdit *pEditT, QLineEdit *pEditTT) +{ + std::string strT = pEditT->text().toStdString(); + t_real dT = tl::str_to_var(strT); + std::string strTT = tl::var_to_str(dT*2., g_iPrec); + pEditTT->setText(strTT.c_str()); +} + +void NeutronDlg::RealThetaEdited() { SetEditTT(editBraggDirT, editBraggDirTT); } +void NeutronDlg::RecipThetaEdited() { SetEditTT(editBraggReciT, editBraggReciTT); } + + +void NeutronDlg::SetEditT(QLineEdit *pEditT, QLineEdit *pEditTT) +{ + std::string strTT = pEditTT->text().toStdString(); + t_real dTT = tl::str_to_var(strTT); + std::string strT = tl::var_to_str(dTT*0.5, g_iPrec); + pEditT->setText(strT.c_str()); +} + +void NeutronDlg::RealTwoThetaEdited() { SetEditT(editBraggDirT, editBraggDirTT); } +void NeutronDlg::RecipTwoThetaEdited() { SetEditT(editBraggReciT, editBraggReciTT); } + + +void NeutronDlg::CalcBraggReal() +{ + std::string strN = editBraggDirN->text().toStdString(); + std::string strLam = editBraggDirLam->text().toStdString(); + std::string strD = editBraggDirD->text().toStdString(); + std::string strTT = editBraggDirTT->text().toStdString(); + + int iOrder = tl::str_to_var(strN); + tl::t_length_si lam = tl::str_to_var(strLam)*angs; + tl::t_length_si d = tl::str_to_var(strD)*angs; + tl::t_angle_si tt = tl::d2r(tl::str_to_var(strTT))*rads; + + if(radioBraggDirLam->isChecked()) + { + lam = tl::bragg_real_lam(d, tt, t_real(iOrder)); + std::string strLam = tl::var_to_str(t_real(lam/angs), g_iPrec); + editBraggDirLam->setText(strLam.c_str()); + } + else if(radioBraggDirD->isChecked()) + { + d = tl::bragg_real_d(lam, tt, t_real(iOrder)); + std::string strD = tl::var_to_str(t_real(d/angs), g_iPrec); + editBraggDirD->setText(strD.c_str()); + } + else if(radioBraggDirTT->isChecked()) + { + tt = tl::bragg_real_twotheta(d, lam, t_real(iOrder)); + std::string strTT = tl::var_to_str(tl::r2d(tt/rads), g_iPrec); + std::string strT = tl::var_to_str(tl::r2d(t_real(0.5)*tt/rads), g_iPrec); + editBraggDirTT->setText(strTT.c_str()); + editBraggDirT->setText(strT.c_str()); + } +} + +void NeutronDlg::CalcBraggRecip() +{ + std::string strN = editBraggReciN->text().toStdString(); + std::string strLam = editBraggReciLam->text().toStdString(); + std::string strQ = editBraggReciQ->text().toStdString(); + std::string strTT = editBraggReciTT->text().toStdString(); + + int iOrder = tl::str_to_var(strN); + tl::t_length_si lam = tl::str_to_var(strLam)*angs; + tl::t_wavenumber_si Q = tl::str_to_var(strQ)/angs; + tl::t_angle_si tt = tl::d2r(tl::str_to_var(strTT))*rads; + + if(radioBraggReciLam->isChecked()) + { + lam = tl::bragg_recip_lam(Q, tt, t_real(iOrder)); + std::string strLam = tl::var_to_str(t_real(lam/angs), g_iPrec); + editBraggReciLam->setText(strLam.c_str()); + } + else if(radioBraggReciQ->isChecked()) + { + Q = tl::bragg_recip_Q(lam, tt, t_real(iOrder)); + std::string strQ = tl::var_to_str(t_real(Q*angs), g_iPrec); + editBraggReciQ->setText(strQ.c_str()); + } + else if(radioBraggReciTT->isChecked()) + { + tt = tl::bragg_recip_twotheta(Q, lam, t_real(iOrder)); + std::string strTT = tl::var_to_str(tl::r2d(tt/rads), g_iPrec); + std::string strT = tl::var_to_str(tl::r2d(t_real(0.5)*tt/rads), g_iPrec); + editBraggReciTT->setText(strTT.c_str()); + editBraggReciT->setText(strT.c_str()); + } +} + + +// ----------------------------------------------------------------------------- + +void NeutronDlg::Eval(const QString& _str) +{ + std::string str = _str.toStdString(); + std::pair pairRes = tl::eval_expr(str); + tl::set_eps_0(pairRes.second); + + if(!pairRes.first) + editEvalRes->setText("invalid"); + else + editEvalRes->setText(tl::var_to_str(pairRes.second, g_iPrec).c_str()); +} + +// ----------------------------------------------------------------------------- + + +void NeutronDlg::accept() +{ + if(m_pSettings) + { + m_pSettings->setValue("neutron_props/geo", saveGeometry()); + m_pSettings->setValue("neutron_props/lam", editLam->text()); + } + + QDialog::accept(); +} + +void NeutronDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + +#include "NeutronDlg.moc" diff --git a/dialogs/NeutronDlg.h b/dialogs/NeutronDlg.h new file mode 100644 index 0000000..f6c422f --- /dev/null +++ b/dialogs/NeutronDlg.h @@ -0,0 +1,58 @@ +/* + * Neutron Properties Dialog (was: old formula dialog) + * @author Tobias Weber + * @date jul-2013, 28-may-2014 + * @license GPLv2 + */ + +#ifndef __NEUTRON_DLG_H__ +#define __NEUTRON_DLG_H__ + +#include +#include +#include "ui/ui_neutrons.h" + + +class NeutronDlg : public QDialog, Ui::NeutronDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + + protected: + void setupConstants(); + + public: + NeutronDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~NeutronDlg(); + + protected slots: + void CalcNeutronLam(); + void CalcNeutronk(); + void CalcNeutronv(); + void CalcNeutronE(); + void CalcNeutronOm(); + void CalcNeutronF(); + void CalcNeutronT(); + + void RealThetaEdited(); + void RecipThetaEdited(); + void RealTwoThetaEdited(); + void RecipTwoThetaEdited(); + void CalcBraggReal(); + void CalcBraggRecip(); + + void EnableRealEdits(); + void EnableRecipEdits(); + + void Eval(const QString&); + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + + static void SetEditTT(QLineEdit *pEditT, QLineEdit *pEditTT); + static void SetEditT(QLineEdit *pEditT, QLineEdit *pEditTT); +}; + + +#endif diff --git a/dialogs/PowderDlg.cpp b/dialogs/PowderDlg.cpp new file mode 100644 index 0000000..2253e4d --- /dev/null +++ b/dialogs/PowderDlg.cpp @@ -0,0 +1,779 @@ +/** + * Powder Line Dialog + * @author Tobias Weber + * @date 2013, 2-dec-2014 + * @license GPLv2 + */ + +#include "PowderDlg.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/powder.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/linalg.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" +#include "libs/formfactors/formfact.h" +#include "libs/qthelper.h" + +#include +#include + +#include +#include + +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); + +namespace ublas = boost::numeric::ublas; +namespace algo = boost::algorithm; + +using t_mat = ublas::matrix; +using t_vec = ublas::vector; + +#define TABLE_ANGLE 0 +#define TABLE_Q 1 +#define TABLE_PEAK 2 +#define TABLE_MULT 3 +#define TABLE_FN 4 +#define TABLE_IN 5 +#define TABLE_FX 6 +#define TABLE_IX 7 + +PowderDlg::PowderDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett), + m_pmapSpaceGroups(SpaceGroups::GetInstance()->get_space_groups()) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + btnAtoms->setEnabled(g_bHasScatlens); + + + // ------------------------------------------------------------------------- + // plot stuff + m_plotwrapN.reset(new QwtPlotWrapper(plotN)); + m_plotwrapN->GetCurve(0)->setTitle("Neutron Powder Pattern"); + m_plotwrapN->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Scattering Angle"); + m_plotwrapN->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Intensity"); + if(m_plotwrapN->HasTrackerSignal()) + connect(m_plotwrapN->GetPicker(), SIGNAL(moved(const QPointF&)), + this, SLOT(cursorMoved(const QPointF&))); + + m_plotwrapX.reset(new QwtPlotWrapper(plotX)); + m_plotwrapX->GetCurve(0)->setTitle("X-Ray Powder Pattern"); + m_plotwrapX->GetPlot()->setAxisTitle(QwtPlot::xBottom, "Scattering Angle"); + m_plotwrapX->GetPlot()->setAxisTitle(QwtPlot::yLeft, "Intensity"); + if(m_plotwrapX->HasTrackerSignal()) + connect(m_plotwrapX->GetPicker(), SIGNAL(moved(const QPointF&)), + this, SLOT(cursorMoved(const QPointF&))); + // ------------------------------------------------------------------------- + + + btnSave->setIcon(load_icon("res/document-save.svg")); + btnLoad->setIcon(load_icon("res/document-open.svg")); + + tablePowderLines->horizontalHeader()->setVisible(true); + tablePowderLines->verticalHeader()->setDefaultSectionSize(tablePowderLines->verticalHeader()->defaultSectionSize()*1.4); + tablePowderLines->setColumnWidth(TABLE_ANGLE, 75); + tablePowderLines->setColumnWidth(TABLE_Q, 75); + tablePowderLines->setColumnWidth(TABLE_PEAK, 75); + tablePowderLines->setColumnWidth(TABLE_MULT, 50); + tablePowderLines->setColumnWidth(TABLE_FN, 75); + tablePowderLines->setColumnWidth(TABLE_FX, 75); + tablePowderLines->setColumnWidth(TABLE_IN, 75); + tablePowderLines->setColumnWidth(TABLE_IX, 75); + + std::vector vecEditsUC = {editA, editB, editC, editAlpha, editBeta, editGamma}; + for(QLineEdit* pEdit : vecEditsUC) + { + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CheckCrystalType())); + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcPeaks())); + } + QObject::connect(spinLam, SIGNAL(valueChanged(double)), this, SLOT(CalcPeaks())); + QObject::connect(spinOrder, SIGNAL(valueChanged(int)), this, SLOT(CalcPeaks())); + QObject::connect(checkUniquePeaks, SIGNAL(toggled(bool)), this, SLOT(CalcPeaks())); + + QObject::connect(editSpaceGroupsFilter, SIGNAL(textChanged(const QString&)), this, SLOT(RepopulateSpaceGroups())); + QObject::connect(comboSpaceGroups, SIGNAL(currentIndexChanged(int)), this, SLOT(SpaceGroupChanged())); + + connect(btnSaveTable, SIGNAL(clicked()), this, SLOT(SaveTable())); + connect(btnSave, SIGNAL(clicked()), this, SLOT(SavePowder())); + connect(btnLoad, SIGNAL(clicked()), this, SLOT(LoadPowder())); + connect(btnAtoms, SIGNAL(clicked()), this, SLOT(ShowAtomDlg())); + + m_bDontCalc = 0; + RepopulateSpaceGroups(); + CalcPeaks(); + + setAcceptDrops(1); + + if(m_pSettings && m_pSettings->contains("powder/geo")) + restoreGeometry(m_pSettings->value("powder/geo").toByteArray()); +} + +PowderDlg::~PowderDlg() +{} + + +void PowderDlg::PlotPowderLines(const std::vector& vecLines) +{ + const unsigned int NUM_POINTS = 512; + + using t_iter = typename std::vector::const_iterator; + std::pair pairMinMax = + boost::minmax_element(vecLines.begin(), vecLines.end(), + [](const PowderLine* pLine1, const PowderLine* pLine2) ->bool + { + return pLine1->dAngle <= pLine2->dAngle; + }); + + t_real dMinTT = 0., dMaxTT = 0.; + if(pairMinMax.first!=vecLines.end() && pairMinMax.second!=vecLines.end()) + { + dMinTT = (*pairMinMax.first)->dAngle; + dMaxTT = (*pairMinMax.second)->dAngle; + + dMinTT -= tl::d2r(10.); + dMaxTT += tl::d2r(10.); + if(dMinTT < 0.) dMinTT = 0.; + } + + m_vecTT.clear(); + m_vecTTx.clear(); + m_vecInt.clear(); + m_vecIntx.clear(); + + m_vecTT.reserve(NUM_POINTS); + m_vecTTx.reserve(NUM_POINTS); + m_vecInt.reserve(NUM_POINTS); + m_vecIntx.reserve(NUM_POINTS); + + for(unsigned int iPt=0; iPtdAngle; + + t_real dPeakInt = pLine->dIn; + t_real dPeakIntX = pLine->dIx; + if(dPeakInt < 0.) dPeakInt = 1.; + if(dPeakIntX < 0.) dPeakIntX = 1.; + + constexpr t_real dSig = 0.25; + dInt += tl::gauss_model(tl::r2d(dTT), tl::r2d(dPeakX), dSig, dPeakInt, 0.); + dIntX += tl::gauss_model(tl::r2d(dTT), tl::r2d(dPeakX), dSig, dPeakIntX, 0.); + } + + m_vecTT.push_back(tl::r2d(dTT)); + m_vecTTx.push_back(tl::r2d(dTT)); + m_vecInt.push_back(dInt); + m_vecIntx.push_back(dIntX); + } + + set_qwt_data()(*m_plotwrapN, m_vecTT, m_vecInt); + set_qwt_data()(*m_plotwrapX, m_vecTTx, m_vecIntx); +} + + +void PowderDlg::CalcPeaks() +{ + try + { + if(m_bDontCalc) return; + static const unsigned int iPrec = g_iPrec; + const bool bWantUniquePeaks = checkUniquePeaks->isChecked(); + + const t_real dA = editA->text().toDouble(); + const t_real dB = editB->text().toDouble(); + const t_real dC = editC->text().toDouble(); + const t_real dAlpha = tl::d2r(editAlpha->text().toDouble()); + const t_real dBeta = tl::d2r(editBeta->text().toDouble()); + const t_real dGamma = tl::d2r(editGamma->text().toDouble()); + + const t_real dLam = spinLam->value(); + const int iOrder = spinOrder->value(); + //tl::log_debug("Lambda = ", dLam, ", order = ", iOrder); + + tl::Lattice lattice(dA, dB, dC, dAlpha, dBeta, dGamma); + tl::Lattice recip = lattice.GetRecip(); + + const t_mat matA = lattice.GetMetric(); + //const t_mat matB = recip.GetMetric(); + + const SpaceGroup* pSpaceGroup = GetCurSpaceGroup(); + + + // ---------------------------------------------------------------------------- + // structure factor stuff + std::shared_ptr> lstsl = ScatlenList::GetInstance(); + std::shared_ptr> lstff = FormfactList::GetInstance(); + + std::vector vecElems; + std::vector vecAllAtoms, vecAllAtomsFrac; + std::vector> vecScatlens; + std::vector vecAllAtomTypes; + std::vector vecFormfacts; + + const std::vector* pvecSymTrafos = nullptr; + if(pSpaceGroup) + pvecSymTrafos = &pSpaceGroup->GetTrafos(); + + if(pvecSymTrafos && pvecSymTrafos->size() && g_bHasFormfacts && + g_bHasScatlens && m_vecAtoms.size()) + { + std::vector vecAtoms; + std::vector vecNames; + for(std::size_t iAtom=0; iAtom + (*pvecSymTrafos, vecAtoms, &vecNames, matA, + t_real(0), t_real(1), g_dEps); + + for(const std::string& strElem : vecElems) + { + const ScatlenList::elem_type* pElem = lstsl->Find(strElem); + vecScatlens.push_back(pElem ? pElem->GetCoherent() : std::complex(0.,0.)); + if(!pElem) + tl::log_err("Element \"", strElem, "\" not found in scattering length table.", + " Using b=0."); + } + } + // ---------------------------------------------------------------------------- + + + std::map mapPeaks; + tl::Powder powder; + powder.SetRecipLattice(&recip); + + for(int ih=iOrder; ih>=-iOrder; --ih) + for(int ik=iOrder; ik>=-iOrder; --ik) + for(int il=iOrder; il>=-iOrder; --il) + { + if(ih==0 && ik==0 && il==0) continue; + if(pSpaceGroup && !pSpaceGroup->HasReflection(ih, ik, il)) + continue; + + + t_vec vecBragg = recip.GetPos(ih, ik, il); + t_real dQ = ublas::norm_2(vecBragg); + if(tl::is_nan_or_inf(dQ)) continue; + + t_real dAngle = tl::bragg_recip_twotheta(dQ/angs, dLam*angs, t_real(1.)) / tl::get_one_radian(); + if(tl::is_nan_or_inf(dAngle)) continue; + + //std::cout << "Q = " << dQ << ", angle = " << (dAngle/M_PI*180.) << std::endl; + + + t_vec vechkl = tl::make_vec({t_real(ih), t_real(ik), t_real(il)}); + t_real dF = -1., dI = -1.; + t_real dFx = -1., dIx = -1.; + + // ---------------------------------------------------------------------------- + // structure factor stuff + if(vecScatlens.size()) + { + std::complex cF = + tl::structfact, t_vec, std::vector> + (vecAllAtoms, vecBragg, vecScatlens); + t_real dFsq = (std::conj(cF)*cF).real(); + dF = std::sqrt(dFsq); + tl::set_eps_0(dF, g_dEps); + + t_real dLor = tl::lorentz_factor(dAngle); + dI = dFsq*dLor; + } + + + + vecFormfacts.clear(); + if(g_bHasFormfacts) + { + for(std::size_t iAtom=0; iAtom::elem_type* pElemff = lstff->Find(vecElems[iAtom]); + + if(pElemff == nullptr) + { + tl::log_err("Cannot get form factor for \"", vecElems[iAtom], "\"."); + vecFormfacts.clear(); + break; + } + + t_real dFF = pElemff->GetFormfact(dQ); + vecFormfacts.push_back(dFF); + } + } + + if(vecFormfacts.size()) + { + std::complex cFx = + tl::structfact + (vecAllAtoms, vecBragg, vecFormfacts); + + t_real dFxsq = (std::conj(cFx)*cFx).real(); + dFx = std::sqrt(dFxsq); + tl::set_eps_0(dFx, g_dEps); + + t_real dLor = tl::lorentz_factor(dAngle)*tl::lorentz_pol_factor(dAngle); + dIx = dFxsq*dLor; + } + // ---------------------------------------------------------------------------- + + + bool bHasPeak = 0; + if(bWantUniquePeaks) + bHasPeak = powder.HasUniquePeak(ih, ik, il, dF); + powder.AddPeak(ih, ik, il, dF); + if(bHasPeak) + continue; + + + // using angle and F as hash for the set + std::ostringstream ostrAngle; + ostrAngle.precision(iPrec); + ostrAngle << tl::r2d(dAngle) << " " << dF; + std::string strAngle = ostrAngle.str(); + //std::cout << strAngle << std::endl; + + std::ostringstream ostrPeak; + ostrPeak << "(" << /*std::abs*/(ih) << /*std::abs*/(ik) << /*std::abs*/(il) << ")"; + + if(mapPeaks[ostrAngle.str()].strPeaks.length()!=0) + mapPeaks[strAngle].strPeaks += ", "; + + mapPeaks[strAngle].strPeaks += ostrPeak.str(); + mapPeaks[strAngle].dAngle = dAngle; + mapPeaks[strAngle].dQ = dQ; + + mapPeaks[strAngle].h = /*std::abs*/(ih); + mapPeaks[strAngle].k = /*std::abs*/(ik); + mapPeaks[strAngle].l = /*std::abs*/(il); + + mapPeaks[strAngle].dFn = dF; + mapPeaks[strAngle].dIn = dI; + mapPeaks[strAngle].dFx = dFx; + mapPeaks[strAngle].dIx = dIx; + } + + //std::cout << powder << std::endl; + std::vector vecPowderLines; + //std::cout << "number of peaks: " << mapPeaks.size() << std::endl; + vecPowderLines.reserve(mapPeaks.size()); + + + for(auto& pair : mapPeaks) + { + pair.second.strAngle = tl::var_to_str(tl::r2d(pair.second.dAngle), iPrec); + pair.second.strQ = tl::var_to_str(pair.second.dQ, iPrec); + pair.second.iMult = powder.GetMultiplicity(pair.second.h, pair.second.k, pair.second.l, pair.second.dFn); + + pair.second.dIn *= t_real(pair.second.iMult); + pair.second.dIx *= t_real(pair.second.iMult); + + vecPowderLines.push_back(&pair.second); + } + + + std::sort(vecPowderLines.begin(), vecPowderLines.end(), + [](const PowderLine* pLine1, const PowderLine* pLine2) -> bool + { return pLine1->dAngle < pLine2->dAngle; }); + + + const bool bSortTable = tablePowderLines->isSortingEnabled(); + tablePowderLines->setSortingEnabled(0); + + const int iNumRows = vecPowderLines.size(); + tablePowderLines->setRowCount(iNumRows); + + for(int iRow=0; iRowitem(iRow, iCol)) + { + if(iCol == TABLE_PEAK) + tablePowderLines->setItem(iRow, iCol, new QTableWidgetItem()); + else if(iCol == TABLE_MULT) + tablePowderLines->setItem(iRow, iCol, new QTableWidgetItemWrapper()); + else + tablePowderLines->setItem(iRow, iCol, new QTableWidgetItemWrapper()); + } + } + + std::string strMult = tl::var_to_str(vecPowderLines[iRow]->iMult, iPrec); + std::string strFn, strIn, strFx, strIx; + if(vecPowderLines[iRow]->dFn >= 0.) + strFn = tl::var_to_str(vecPowderLines[iRow]->dFn, iPrec); + if(vecPowderLines[iRow]->dIn >= 0.) + strIn = tl::var_to_str(vecPowderLines[iRow]->dIn, iPrec); + if(vecPowderLines[iRow]->dFx >= 0.) + strFx = tl::var_to_str(vecPowderLines[iRow]->dFx, iPrec); + if(vecPowderLines[iRow]->dIx >= 0.) + strIx = tl::var_to_str(vecPowderLines[iRow]->dIx, iPrec); + + tablePowderLines->item(iRow, TABLE_PEAK)->setText(vecPowderLines[iRow]->strPeaks.c_str()); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_ANGLE))-> + SetValue(vecPowderLines[iRow]->dAngle, vecPowderLines[iRow]->strAngle); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_Q))-> + SetValue(vecPowderLines[iRow]->dQ, vecPowderLines[iRow]->strQ); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_MULT))-> + SetValue(vecPowderLines[iRow]->iMult, strMult); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_FN))-> + SetValue(vecPowderLines[iRow]->dFn, strFn); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_IN))-> + SetValue(vecPowderLines[iRow]->dIn, strIn); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_FX))-> + SetValue(vecPowderLines[iRow]->dFx, strFx); + dynamic_cast*>(tablePowderLines->item(iRow, TABLE_IX))-> + SetValue(vecPowderLines[iRow]->dIx, strIx); + } + + tablePowderLines->setSortingEnabled(bSortTable); + PlotPowderLines(vecPowderLines); + labelStatus->setText("OK."); + } + catch(const std::exception& ex) + { + //labelStatus->setText(QString("Error: ") + ex.what()); + labelStatus->setText("Error."); + tl::log_err("Cannot calculate powder peaks: ", ex.what()); + } +} + + +const SpaceGroup* PowderDlg::GetCurSpaceGroup() const +{ + SpaceGroup* pSpaceGroup = 0; + int iSpaceGroupIdx = comboSpaceGroups->currentIndex(); + if(iSpaceGroupIdx != 0) + pSpaceGroup = (SpaceGroup*)comboSpaceGroups->itemData(iSpaceGroupIdx).value(); + return pSpaceGroup; +} + +void PowderDlg::SpaceGroupChanged() +{ + m_crystalsys = CrystalSystem::CRYS_NOT_SET; + std::string strCryTy = ""; + + const SpaceGroup* pSpaceGroup = GetCurSpaceGroup(); + if(pSpaceGroup) + { + m_crystalsys = pSpaceGroup->GetCrystalSystem(); + strCryTy = pSpaceGroup->GetCrystalSystemName(); + } + editCrystalSystem->setText(strCryTy.c_str()); + + CheckCrystalType(); + CalcPeaks(); +} + +void PowderDlg::RepopulateSpaceGroups() +{ + if(!m_pmapSpaceGroups) + return; + + for(int iCnt=comboSpaceGroups->count()-1; iCnt>0; --iCnt) + comboSpaceGroups->removeItem(iCnt); + + std::string strFilter = editSpaceGroupsFilter->text().toStdString(); + + for(const SpaceGroups::t_mapSpaceGroups::value_type& pair : *m_pmapSpaceGroups) + { + const std::string& strName = pair.second.GetName(); + + typedef const boost::iterator_range t_striterrange; + if(strFilter!="" && + !boost::ifind_first(t_striterrange(strName.begin(), strName.end()), + t_striterrange(strFilter.begin(), strFilter.end()))) + continue; + + comboSpaceGroups->insertItem(comboSpaceGroups->count(), + strName.c_str(), QVariant::fromValue((void*)&pair.second)); + } +} + +void PowderDlg::CheckCrystalType() +{ + set_crystal_system_edits(m_crystalsys, editA, editB, editC, + editAlpha, editBeta, editGamma); +} + +void PowderDlg::SavePowder() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + m_pSettings->value("powder/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getSaveFileName(this, + "Save Powder Configuration", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + + if(qstrFile == "") + return; + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + std::map mapConf; + Save(mapConf, strXmlRoot); + + tl::Prop xml; + xml.Add(mapConf); + + bool bOk = xml.Save(strFile.c_str(), tl::PropType::XML); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not save powder file."); + + if(bOk && m_pSettings) + m_pSettings->setValue("powder/last_dir", QString(strDir.c_str())); +} + +void PowderDlg::dragEnterEvent(QDragEnterEvent *pEvt) +{ + if(pEvt) pEvt->accept(); +} + +void PowderDlg::dropEvent(QDropEvent *pEvt) +{ + if(!pEvt) return; + const QMimeData* pMime = pEvt->mimeData(); + if(!pMime) return; + + std::string strFiles = pMime->text().toStdString(); + std::vector vecFiles; + tl::get_tokens(strFiles, "\n", vecFiles); + if(vecFiles.size() > 1) + tl::log_warn("More than one file dropped, using first one."); + + if(vecFiles.size() >= 1) + { + std::string& strFile = vecFiles[0]; + tl::trim(strFile); + + const std::string strHead = "file://"; + if(algo::starts_with(strFile, strHead)) + algo::replace_head(strFile, strHead.length(), ""); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load powder file."); + return; + } + + const std::string strXmlRoot("taz/"); + Load(xml, strXmlRoot); + } +} + +void PowderDlg::LoadPowder() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + strDirLast = m_pSettings->value("powder/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getOpenFileName(this, + "Open Powder Configuration", strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + if(qstrFile == "") + return; + + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load powder file."); + return; + } + + Load(xml, strXmlRoot); + if(m_pSettings) + m_pSettings->setValue("powder/last_dir", QString(strDir.c_str())); +} + +void PowderDlg::Save(std::map& mapConf, const std::string& strXmlRoot) +{ + mapConf[strXmlRoot + "sample/a"] = editA->text().toStdString(); + mapConf[strXmlRoot + "sample/b"] = editB->text().toStdString(); + mapConf[strXmlRoot + "sample/c"] = editC->text().toStdString(); + + mapConf[strXmlRoot + "sample/alpha"] = editAlpha->text().toStdString(); + mapConf[strXmlRoot + "sample/beta"] = editBeta->text().toStdString(); + mapConf[strXmlRoot + "sample/gamma"] = editGamma->text().toStdString(); + + mapConf[strXmlRoot + "powder/maxhkl"] = tl::var_to_str(spinOrder->value(), g_iPrec); + mapConf[strXmlRoot + "powder/lambda"] = tl::var_to_str(spinLam->value(), g_iPrec); + + mapConf[strXmlRoot + "sample/spacegroup"] = comboSpaceGroups->currentText().toStdString(); + + // atom positions + mapConf[strXmlRoot + "sample/atoms/num"] = tl::var_to_str(m_vecAtoms.size()); + for(std::size_t iAtom=0; iAtom& atom = m_vecAtoms[iAtom]; + + std::string strAtomNr = tl::var_to_str(iAtom); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/name"] = + atom.strAtomName; + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/x"] = + tl::var_to_str(atom.vecPos[0], g_iPrec); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/y"] = + tl::var_to_str(atom.vecPos[1], g_iPrec); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/z"] = + tl::var_to_str(atom.vecPos[2], g_iPrec); + } +} + +void PowderDlg::Load(tl::Prop& xml, const std::string& strXmlRoot) +{ + m_bDontCalc = 1; + bool bOk=0; + + editA->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/a").c_str(), 5., &bOk), g_iPrec).c_str()); + editB->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/b").c_str(), 5., &bOk), g_iPrec).c_str()); + editC->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/c").c_str(), 5., &bOk), g_iPrec).c_str()); + + editAlpha->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/alpha").c_str(), 90., &bOk), g_iPrec).c_str()); + editBeta->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/beta").c_str(), 90., &bOk), g_iPrec).c_str()); + editGamma->setText(tl::var_to_str(xml.Query((strXmlRoot + "sample/gamma").c_str(), 90., &bOk), g_iPrec).c_str()); + + spinOrder->setValue(xml.Query((strXmlRoot + "powder/maxhkl").c_str(), 10, &bOk)); + spinLam->setValue(xml.Query((strXmlRoot + "powder/lambda").c_str(), 5., &bOk)); + + std::string strSpaceGroup = xml.Query((strXmlRoot + "sample/spacegroup").c_str(), "", &bOk); + tl::trim(strSpaceGroup); + if(bOk) + { + editSpaceGroupsFilter->clear(); + int iSGIdx = comboSpaceGroups->findText(strSpaceGroup.c_str()); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); + } + + + // atom positions + m_vecAtoms.clear(); + unsigned int iNumAtoms = xml.Query((strXmlRoot + "sample/atoms/num").c_str(), 0, &bOk); + if(bOk) + { + m_vecAtoms.reserve(iNumAtoms); + + for(std::size_t iAtom=0; iAtom atom; + atom.vecPos.resize(3,0); + + std::string strNr = tl::var_to_str(iAtom); + atom.strAtomName = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/name").c_str(), ""); + atom.vecPos[0] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/x").c_str(), 0.); + atom.vecPos[1] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/y").c_str(), 0.); + atom.vecPos[2] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/z").c_str(), 0.); + + m_vecAtoms.push_back(atom); + } + } + + + m_bDontCalc = 0; + CalcPeaks(); +} + + +void PowderDlg::SaveTable() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_pSettings ? m_pSettings->value("powder/last_dir_table", ".").toString() : "."; + QString strFile = QFileDialog::getSaveFileName(this, + "Save Table", strDirLast, "Data files (*.dat *.DAT)", nullptr, fileopt); + + if(strFile != "") + { + if(!save_table(strFile.toStdString().c_str(), tablePowderLines)) + QMessageBox::critical(this, "Error", "Could not save table data."); + } +} + + +void PowderDlg::ApplyAtoms(const std::vector>& vecAtoms) +{ + m_vecAtoms = vecAtoms; + CalcPeaks(); +} + +void PowderDlg::ShowAtomDlg() +{ + if(!m_pAtomsDlg) + { + m_pAtomsDlg = new AtomsDlg(this, m_pSettings); + m_pAtomsDlg->setWindowTitle(m_pAtomsDlg->windowTitle() + QString(" (Powder)")); + + QObject::connect(m_pAtomsDlg, SIGNAL(ApplyAtoms(const std::vector>&)), + this, SLOT(ApplyAtoms(const std::vector>&))); + } + + m_pAtomsDlg->SetAtoms(m_vecAtoms); + m_pAtomsDlg->show(); + m_pAtomsDlg->activateWindow(); +} + +void PowderDlg::cursorMoved(const QPointF& pt) +{ + const t_real dX = pt.x(); + const t_real dY = pt.y(); + + const std::wstring strTh = tl::get_spec_char_utf16("theta"); + std::wostringstream ostr; + ostr.precision(g_iPrecGfx); + ostr << L"2" << strTh << L" = " << dX << L", "; + ostr << L"I = " << dY; + + labelStatus->setText(QString::fromWCharArray(ostr.str().c_str())); +} + +void PowderDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("powder/geo", saveGeometry()); + + QDialog::accept(); +} + +void PowderDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "PowderDlg.moc" diff --git a/dialogs/PowderDlg.h b/dialogs/PowderDlg.h new file mode 100644 index 0000000..028da88 --- /dev/null +++ b/dialogs/PowderDlg.h @@ -0,0 +1,103 @@ +/** + * Powder Line Dialog + * @author Tobias Weber + * @date 2013, 2-dec-2014 + * @license GPLv2 + */ + +#ifndef __POWDER_DLG_H__ +#define __POWDER_DLG_H__ + +#include +#include +#include +#include +#include "ui/ui_powder.h" + +#include +#include +#include +#include + +#include "libs/spacegroups/spacegroup.h" +#include "libs/qthelper.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "tlibs/file/prop.h" +#include "AtomsDlg.h" + + +struct PowderLine +{ + int h, k, l; + + t_real_glob dAngle; + std::string strAngle; + + t_real_glob dQ; + std::string strQ; + + std::string strPeaks; + + unsigned int iMult; + t_real_glob dFn, dFx; // neutron/xray structure factors + t_real_glob dIn, dIx; // neutron/xray intensities +}; + + +class PowderDlg : public QDialog, Ui::PowderDlg +{ Q_OBJECT + protected: + std::vector m_vecTT, m_vecInt; + std::vector m_vecTTx, m_vecIntx; + + std::unique_ptr m_plotwrapN; + std::unique_ptr m_plotwrapX; + + protected: + bool m_bDontCalc = 1; + QSettings *m_pSettings = 0; + + CrystalSystem m_crystalsys = CRYS_NOT_SET; + const SpaceGroups::t_mapSpaceGroups* m_pmapSpaceGroups; + + AtomsDlg *m_pAtomsDlg = nullptr; + std::vector> m_vecAtoms; + + public: + PowderDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~PowderDlg(); + + protected: + void PlotPowderLines(const std::vector& vecLines); + + protected slots: + void CalcPeaks(); + + void CheckCrystalType(); + void SpaceGroupChanged(); + void RepopulateSpaceGroups(); + + void SaveTable(); + void SavePowder(); + void LoadPowder(); + + void ShowAtomDlg(); + void ApplyAtoms(const std::vector>&); + + void cursorMoved(const QPointF& pt); + + virtual void dragEnterEvent(QDragEnterEvent *pEvt) override; + virtual void dropEvent(QDropEvent *pEvt) override; + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; + + const SpaceGroup* GetCurSpaceGroup() const; + + void Save(std::map& mapConf, const std::string& strXmlRoot); + void Load(tl::Prop& xml, const std::string& strXmlRoot); +}; + +#endif diff --git a/dialogs/RealParamDlg.cpp b/dialogs/RealParamDlg.cpp new file mode 100644 index 0000000..3bb4b1a --- /dev/null +++ b/dialogs/RealParamDlg.cpp @@ -0,0 +1,181 @@ +/** + * Real Space Parameters + * @author tweber + * @date 2014-2016 + * @license GPLv2 + */ + +#include "RealParamDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/math/math.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/atoms.h" +#include "tlibs/math/nn.h" +#include "tlibs/string/spec_char.h" + +using t_real = t_real_glob; +using t_mat = ublas::matrix; +using t_vec = ublas::vector; + + +RealParamDlg::RealParamDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && + font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + if(m_pSettings && m_pSettings->contains("real_params/geo")) + restoreGeometry(m_pSettings->value("real_params/geo").toByteArray()); +} + +RealParamDlg::~RealParamDlg() {} + +void RealParamDlg::paramsChanged(const RealParams& parms) +{ + this->edit2ThetaM->setText(tl::var_to_str(tl::r2d(parms.dMonoTT), g_iPrec).c_str()); + this->editThetaM->setText(tl::var_to_str(tl::r2d(parms.dMonoT), g_iPrec).c_str()); + + this->edit2ThetaS->setText(tl::var_to_str(tl::r2d(parms.dSampleTT), g_iPrec).c_str()); + this->editThetaS->setText(tl::var_to_str(tl::r2d(parms.dSampleT), g_iPrec).c_str()); + + this->edit2ThetaA->setText(tl::var_to_str(tl::r2d(parms.dAnaTT), g_iPrec).c_str()); + this->editThetaA->setText(tl::var_to_str(tl::r2d(parms.dAnaT), g_iPrec).c_str()); + + + this->editLenMonoSample->setText(tl::var_to_str(parms.dLenMonoSample, g_iPrec).c_str()); + this->editLenSampleAna->setText(tl::var_to_str(parms.dLenSampleAna, g_iPrec).c_str()); + this->editLenAnaDet->setText(tl::var_to_str(parms.dLenAnaDet, g_iPrec).c_str()); +} + + +void RealParamDlg::CrystalChanged(const tl::Lattice& latt, + const tl::Lattice& recip, const SpaceGroup* pSG, + const std::vector>* pAtoms) +{ + treeNN->clear(); + listAtoms->clear(); + if(!pAtoms || !pSG) return; + + const int iSC = 2; + const t_real dEpsShell = 0.01; + + const std::wstring strAA = tl::get_spec_char_utf16("AA"); + try + { + const t_mat matA = latt.GetMetric(); // frac -> A + //const t_mat matB = recip.GetMetric(); // rlu -> 1/A + const std::vector& vecSymTrafos = pSG->GetTrafos(); + + // all primitive atoms + std::vector vecAtoms, vecAtomsUC, vecAtomsUCFrac, + vecAtomsSC, vecAtomsNN; + for(const AtomPos& atom : *pAtoms) + vecAtoms.push_back(atom.vecPos); + + // all atoms in unit cell + std::vector vecIdxUC, vecIdxSC; + std::tie(std::ignore, vecAtomsUC, vecAtomsUCFrac, vecIdxUC) = + tl::generate_all_atoms + (vecSymTrafos, vecAtoms, nullptr, matA, + t_real(-0.5), t_real(0.5), g_dEps); + + // fill list widget + std::size_t iCurAtom = 0; + for(std::size_t iIdxUC : vecIdxUC) + { + const std::string& strName = (*pAtoms)[iIdxUC].strAtomName; + const t_vec& vecAtom = vecAtomsUC[iCurAtom]; + const t_vec& vecAtomFrac = vecAtomsUCFrac[iCurAtom]; + + std::wostringstream ostr; + ostr.precision(g_iPrec); + ostr << "(" << (iCurAtom+1) << ") " << tl::str_to_wstr(strName); + ostr << "\npos = (" << vecAtom[0] << ", " << vecAtom[1] << ", " << vecAtom[2] << ") " << strAA; + ostr << "\npos = (" << vecAtomFrac[0] << ", " << vecAtomFrac[1] << ", " << vecAtomFrac[2] << ") frac"; + listAtoms->addItem(new QListWidgetItem(QString::fromWCharArray(ostr.str().c_str()))); + + ++iCurAtom; + } + + // all atoms in super cell + std::vector> vecDummy; + std::tie(vecAtomsSC, std::ignore, vecIdxSC) = + tl::generate_supercell + (latt, vecAtomsUC, vecDummy, iSC); + std::vector vecNamesSC; + for(std::size_t iIdxSC : vecIdxSC) + vecNamesSC.push_back((*pAtoms)[vecIdxUC[iIdxSC]].strAtomName); + + // get neighbours of all atoms + for(const AtomPos& atom : *pAtoms) + { + const std::string& strName = atom.strAtomName; + QTreeWidgetItem *pWidParent = new QTreeWidgetItem(treeNN); + pWidParent->setText(0, strName.c_str()); + pWidParent->setExpanded(1); + + const t_vec& vecCentreFrac = atom.vecPos; + t_vec vecCentreAA = tl::mult(matA, vecCentreFrac); + if(tl::is_nan_or_inf(vecCentreFrac) || tl::is_nan_or_inf(vecCentreAA)) + { + tl::log_err("Invalid centre."); + break; + } + + // neighbours + std::vector> vecIdxNN = + tl::get_neighbours + (vecAtomsSC, vecCentreAA, dEpsShell); + + if(vecIdxNN.size() > 1) + { + // only nearest neighbour + for(std::size_t iIdxNN : vecIdxNN[1]) + { + const t_vec vecThisAA = vecAtomsSC[iIdxNN] - vecCentreAA; + const std::string& strThisAtom = vecNamesSC[iIdxNN]; + + QTreeWidgetItem *pWidNN = new QTreeWidgetItem(pWidParent); + pWidNN->setText(0, strThisAtom.c_str()); + + std::wostringstream ostr; + ostr.precision(g_iPrec); + ostr << "(" << vecThisAA[0] << ", " << vecThisAA[1] << ", " << vecThisAA[2] << ") " << strAA; + pWidNN->setText(1, QString::fromWCharArray(ostr.str().c_str())); + } + } + } + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + } +} + + +void RealParamDlg::closeEvent(QCloseEvent *pEvt) +{ + QDialog::closeEvent(pEvt); +} + +void RealParamDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("real_params/geo", saveGeometry()); + + QDialog::accept(); +} + +void RealParamDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "RealParamDlg.moc" diff --git a/dialogs/RealParamDlg.h b/dialogs/RealParamDlg.h new file mode 100644 index 0000000..bb0392c --- /dev/null +++ b/dialogs/RealParamDlg.h @@ -0,0 +1,52 @@ +/** + * Real Space Parameters + * @author tweber + * @date 2014-2016 + * @license GPLv2 + */ + +#ifndef __REAL_PARAMS_H__ +#define __REAL_PARAMS_H__ + +#include +#include +#include + +#include "ui/ui_real_params.h" +#include "libs/globals.h" +#include "libs/spacegroups/spacegroup.h" +#include "tlibs/math/lattice.h" +#include "AtomsDlg.h" + + +struct RealParams +{ + t_real_glob dMonoTT, dSampleTT, dAnaTT; + t_real_glob dMonoT, dSampleT, dAnaT; + t_real_glob dLenMonoSample, dLenSampleAna, dLenAnaDet; +}; + + +class RealParamDlg : public QDialog, Ui::RealParamDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + + public: + RealParamDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~RealParamDlg(); + + public slots: + void paramsChanged(const RealParams& parms); + void CrystalChanged(const tl::Lattice& latt, + const tl::Lattice& recip, + const SpaceGroup* pSG, + const std::vector>* pAtoms); + + protected: + virtual void closeEvent(QCloseEvent *pEvt) override; + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; +}; + +#endif diff --git a/dialogs/RecipParamDlg.cpp b/dialogs/RecipParamDlg.cpp new file mode 100644 index 0000000..6f91178 --- /dev/null +++ b/dialogs/RecipParamDlg.cpp @@ -0,0 +1,227 @@ +/** + * Reciprocal Space Parameters + * @author tweber + * @date 26-mar-2014 + * @license GPLv2 + */ + +#include "RecipParamDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/math/math.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/neutrons.h" + +namespace ublas = boost::numeric::ublas; +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_time_si sec = tl::get_one_second(); +static const tl::t_length_si meter = tl::get_one_meter(); + + +RecipParamDlg::RecipParamDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + this->setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + +#if QT_VER >= 5 + QObject::connect(editKi, &QLineEdit::textChanged, this, &RecipParamDlg::KiChanged); + QObject::connect(editKf, &QLineEdit::textChanged, this, &RecipParamDlg::KfChanged); + + QObject::connect(btnUseG, &QAbstractButton::clicked, this, &RecipParamDlg::SetGOrigin); + QObject::connect(editOriginH, &QLineEdit::textEdited, this, &RecipParamDlg::OriginChanged); + QObject::connect(editOriginK, &QLineEdit::textEdited, this, &RecipParamDlg::OriginChanged); + QObject::connect(editOriginL, &QLineEdit::textEdited, this, &RecipParamDlg::OriginChanged); + QObject::connect(radioEm, &QRadioButton::toggled, this, &RecipParamDlg::OriginChanged); +#else + QObject::connect(editKi, SIGNAL(textChanged(const QString&)), this, SLOT(KiChanged())); + QObject::connect(editKf, SIGNAL(textChanged(const QString&)), this, SLOT(KfChanged())); + + QObject::connect(btnUseG, SIGNAL(clicked()), this, SLOT(SetGOrigin())); + QObject::connect(editOriginH, SIGNAL(textEdited(const QString&)), this, SLOT(OriginChanged())); + QObject::connect(editOriginK, SIGNAL(textEdited(const QString&)), this, SLOT(OriginChanged())); + QObject::connect(editOriginL, SIGNAL(textEdited(const QString&)), this, SLOT(OriginChanged())); + QObject::connect(radioEm, SIGNAL(toggled(bool)), this, SLOT(OriginChanged())); +#endif + + if(m_pSettings) + { + if(m_pSettings->contains("recip_params/geo")) + restoreGeometry(m_pSettings->value("recip_params/geo").toByteArray()); + if(m_pSettings->contains("recip_params/defs_Em")) + radioEm->setChecked(m_pSettings->value("recip_params/defs_Em").toBool()); + } +} + +RecipParamDlg::~RecipParamDlg() +{} + +void RecipParamDlg::paramsChanged(const RecipParams& parms) +{ + m_params = parms; + + t_real dQ = m_params.dQ; + if(m_params.d2Theta < 0.) + dQ = -dQ; + + t_real dq_rlu = std::sqrt(m_params.q_rlu[0]*m_params.q_rlu[0] + + m_params.q_rlu[1]*m_params.q_rlu[1] + + m_params.q_rlu[2]*m_params.q_rlu[2]); + + this->editKi->setText(tl::var_to_str(m_params.dki, g_iPrec).c_str()); + this->editKf->setText(tl::var_to_str(m_params.dkf, g_iPrec).c_str()); + this->editQ->setText(tl::var_to_str(dQ, g_iPrec).c_str()); + this->editq->setText(tl::var_to_str(m_params.dq, g_iPrec).c_str()); + this->editqrlu->setText(tl::var_to_str(dq_rlu, g_iPrec).c_str()); + this->editE->setText(tl::var_to_str(m_params.dE, g_iPrec).c_str()); + this->edit2Theta->setText(tl::var_to_str(tl::r2d(m_params.d2Theta), g_iPrec).c_str()); + this->editTheta->setText(tl::var_to_str(tl::r2d(m_params.dTheta), g_iPrec).c_str()); + this->editKiQ->setText(tl::var_to_str(tl::r2d(m_params.dKiQ), g_iPrec).c_str()); + this->editKfQ->setText(tl::var_to_str(tl::r2d(m_params.dKfQ), g_iPrec).c_str()); + + this->editQx->setText(tl::var_to_str(-m_params.Q[0], g_iPrec).c_str()); + this->editQy->setText(tl::var_to_str(-m_params.Q[1], g_iPrec).c_str()); + this->editQz->setText(tl::var_to_str(-m_params.Q[2], g_iPrec).c_str()); + this->editQxrlu->setText(tl::var_to_str(-m_params.Q_rlu[0], g_iPrec).c_str()); + this->editQyrlu->setText(tl::var_to_str(-m_params.Q_rlu[1], g_iPrec).c_str()); + this->editQzrlu->setText(tl::var_to_str(-m_params.Q_rlu[2], g_iPrec).c_str()); + + this->editqx->setText(tl::var_to_str(-m_params.q[0], g_iPrec).c_str()); + this->editqy->setText(tl::var_to_str(-m_params.q[1], g_iPrec).c_str()); + this->editqz->setText(tl::var_to_str(-m_params.q[2], g_iPrec).c_str()); + this->editqxrlu->setText(tl::var_to_str(-m_params.q_rlu[0], g_iPrec).c_str()); + this->editqyrlu->setText(tl::var_to_str(-m_params.q_rlu[1], g_iPrec).c_str()); + this->editqzrlu->setText(tl::var_to_str(-m_params.q_rlu[2], g_iPrec).c_str()); + + this->editGx->setText(tl::var_to_str(-m_params.G[0], g_iPrec).c_str()); + this->editGy->setText(tl::var_to_str(-m_params.G[1], g_iPrec).c_str()); + this->editGz->setText(tl::var_to_str(-m_params.G[2], g_iPrec).c_str()); + this->editGxrlu->setText(tl::var_to_str(-m_params.G_rlu[0], g_iPrec).c_str()); + this->editGyrlu->setText(tl::var_to_str(-m_params.G_rlu[1], g_iPrec).c_str()); + this->editGzrlu->setText(tl::var_to_str(-m_params.G_rlu[2], g_iPrec).c_str()); + + + // focus + ublas::vector vecG = tl::make_vec({-m_params.G_rlu[0], -m_params.G_rlu[1], -m_params.G_rlu[2]}); + ublas::vector vecUp = tl::make_vec({m_params.orient_up[0], m_params.orient_up[1], m_params.orient_up[2]}); + ublas::vector vecFm = tl::cross_3(vecG, vecUp); + vecFm /= ublas::norm_2(vecFm); + tl::set_eps_0(vecFm, g_dEps); + + this->editFmx->setText(tl::var_to_str(vecFm[0], g_iPrec).c_str()); + this->editFmy->setText(tl::var_to_str(vecFm[1], g_iPrec).c_str()); + this->editFmz->setText(tl::var_to_str(vecFm[2], g_iPrec).c_str()); + + this->editFpx->setText(tl::var_to_str(-vecFm[0], g_iPrec).c_str()); + this->editFpy->setText(tl::var_to_str(-vecFm[1], g_iPrec).c_str()); + this->editFpz->setText(tl::var_to_str(-vecFm[2], g_iPrec).c_str()); + + + /*if(editOriginH->text().trimmed()=="" || editOriginK->text().trimmed()=="" || editOriginL->text().trimmed()=="") + SetGOrigin();*/ + OriginChanged(); +} + + +void RecipParamDlg::KiChanged() +{ + tl::t_wavenumber_si ki = tl::str_to_var(editKi->text().toStdString()) / angs; + tl::t_energy_si Ei = tl::k2E(ki); + tl::t_length_si lami = tl::k2lam(ki); + tl::t_velocity_si vi = tl::k2v(ki); + + editEi->setText(tl::var_to_str(Ei / meV, g_iPrec).c_str()); + editLami->setText(tl::var_to_str(lami / angs, g_iPrec).c_str()); + editVi->setText(tl::var_to_str(vi*sec/meter, g_iPrec).c_str()); +} + +void RecipParamDlg::KfChanged() +{ + tl::t_wavenumber_si kf = tl::str_to_var(editKf->text().toStdString()) / angs; + tl::t_energy_si Ef = tl::k2E(kf); + tl::t_length_si lamf = tl::k2lam(kf); + tl::t_velocity_si vf = tl::k2v(kf); + + editEf->setText(tl::var_to_str(Ef / meV, g_iPrec).c_str()); + editLamf->setText(tl::var_to_str(lamf / angs, g_iPrec).c_str()); + editVf->setText(tl::var_to_str(vf*sec/meter, g_iPrec).c_str()); +} + + +void RecipParamDlg::SetGOrigin() +{ + editOriginH->setText(editGxrlu->text()); + editOriginK->setText(editGyrlu->text()); + editOriginL->setText(editGzrlu->text()); + + OriginChanged(); +} + +void RecipParamDlg::OriginChanged() +{ + const bool bEm = radioEm->isChecked(); + const t_real dH = tl::str_to_var(editOriginH->text().toStdString()); + const t_real dK = tl::str_to_var(editOriginK->text().toStdString()); + const t_real dL = tl::str_to_var(editOriginL->text().toStdString()); + const t_real dSq = dH*dH + dK*dK + dL*dL; + + const ublas::vector vecQ = tl::make_vec({dH, dK, dL}); + ublas::vector vecUp = tl::make_vec({m_params.orient_up[0], m_params.orient_up[1], m_params.orient_up[2]}); + ublas::vector vecFm = tl::cross_3(vecQ, vecUp); + vecUp /= ublas::norm_2(vecUp); + vecFm /= ublas::norm_2(vecFm); + + if(!bEm) vecFm = -vecFm; + tl::set_eps_0(vecUp, g_dEps); + tl::set_eps_0(vecFm, g_dEps); + + + std::ostringstream ostrDefs; + ostrDefs << "import numpy as np\n\n\n"; + ostrDefs << "origin = np.array([" << dH << ", " << dK << ", " << dL << "])\n\n"; + + ostrDefs << "longdir = origin"; + if(!tl::float_equal(dSq, 1.)) + ostrDefs << " / np.sqrt(" << dSq << ")"; + ostrDefs << "\n"; + + ostrDefs << "transdir = np.array([" << vecFm[0] << ", " << vecFm[1] << ", " << vecFm[2] << "])\n"; + ostrDefs << "updir = np.array([" << vecUp[0] << ", " << vecUp[1] << ", " << vecUp[2] << "])\n\n\n"; + + ostrDefs << "# define some arbitrary direction in the scattering plane here:\n"; + ostrDefs << "# userangle = 45. / 180. * np.pi\n"; + ostrDefs << "# userdir = longdir*np.cos(userangle) + transdir*np.sin(userangle)\n"; + + editDefs->setText(ostrDefs.str().c_str()); +} + + +void RecipParamDlg::closeEvent(QCloseEvent *pEvt) +{ + QDialog::closeEvent(pEvt); +} + +void RecipParamDlg::accept() +{ + if(m_pSettings) + { + m_pSettings->setValue("recip_params/defs_Em", radioEm->isChecked()); + m_pSettings->setValue("recip_params/geo", saveGeometry()); + } + + QDialog::accept(); +} + +void RecipParamDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "RecipParamDlg.moc" diff --git a/dialogs/RecipParamDlg.h b/dialogs/RecipParamDlg.h new file mode 100644 index 0000000..eee01ee --- /dev/null +++ b/dialogs/RecipParamDlg.h @@ -0,0 +1,58 @@ +/** + * Reciprocal Space Parameters + * @author tweber + * @date 26-mar-2014 + * @license GPLv2 + */ + +#ifndef __RECIP_PARAMS_H__ +#define __RECIP_PARAMS_H__ + +#include +#include +#include "libs/globals.h" +#include "ui/ui_recip_params.h" + + +struct RecipParams +{ + t_real_glob dki, dkf; + t_real_glob dE, dQ, dq; + t_real_glob d2Theta, dTheta, dKiQ, dKfQ; + t_real_glob dAngleQVec0; + + t_real_glob Q[3], Q_rlu[3]; + t_real_glob G[3], G_rlu[3], G_rlu_accurate[3]; + t_real_glob q[3], q_rlu[3]; + + t_real_glob orient_0[3], orient_1[3], orient_up[3]; +}; + + +class RecipParamDlg : public QDialog, Ui::RecipParamDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + RecipParams m_params; + + public: + RecipParamDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~RecipParamDlg(); + + public slots: + void paramsChanged(const RecipParams& parms); + + protected slots: + void KiChanged(); + void KfChanged(); + + void SetGOrigin(); + void OriginChanged(); + + protected: + virtual void closeEvent(QCloseEvent *pEvt) override; + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; +}; + +#endif diff --git a/dialogs/SettingsDlg.cpp b/dialogs/SettingsDlg.cpp new file mode 100644 index 0000000..33e7965 --- /dev/null +++ b/dialogs/SettingsDlg.cpp @@ -0,0 +1,356 @@ +/** + * Settings + * @author tweber + * @date 5-dec-2014 + * @license GPLv2 + */ + +#include "SettingsDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#ifndef NO_3D + #include "tlibs/gfx/gl.h" +#endif +#include "libs/globals.h" +#include "libs/globals_qt.h" + +#include +#include +#include +#include + +using t_real = t_real_glob; + +// ----------------------------------------------------------------------------- + + +SettingsDlg::SettingsDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setupUi(this); + + g_fontGen.setStyleHint(QFont::SansSerif); + g_fontGfx.setStyleHint(QFont::SansSerif, QFont::PreferAntialias); + g_fontGL.setStyleHint(QFont::Monospace, QFont::OpenGLCompatible); + setFont(g_fontGen); + +#if QT_VER >= 5 + connect(buttonBox, &QDialogButtonBox::clicked, this, &SettingsDlg::ButtonBoxClicked); + connect(btnGLFont, &QAbstractButton::clicked, this, &SettingsDlg::SelectGLFont); + connect(btnGfxFont, &QAbstractButton::clicked, this, &SettingsDlg::SelectGfxFont); + connect(btnGenFont, &QAbstractButton::clicked, this, &SettingsDlg::SelectGenFont); +#else + connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(ButtonBoxClicked(QAbstractButton*))); + connect(btnGLFont, SIGNAL(clicked()), this, SLOT(SelectGLFont())); + connect(btnGfxFont, SIGNAL(clicked()), this, SLOT(SelectGfxFont())); + connect(btnGenFont, SIGNAL(clicked()), this, SLOT(SelectGenFont())); +#endif + + m_vecEdits = + { + t_tupEdit("net/sample_name", "nicos/sample/samplename", editSampleName), + t_tupEdit("net/lattice", "nicos/sample/lattice", editSampleLattice), + t_tupEdit("net/angles", "nicos/sample/angles", editSampleAngles), + t_tupEdit("net/orient1", "nicos/sample/orient1", editSampleOrient1), + t_tupEdit("net/orient2", "nicos/sample/orient2", editSampleOrient2), + t_tupEdit("net/spacegroup", "nicos/sample/spacegroup", editSampleSG), + t_tupEdit("net/psi0", "nicos/sample/psi0", editSamplePsi0), + + t_tupEdit("net/stheta", "nicos/sth/value", editSampleTheta), + t_tupEdit("net/s2theta", "nicos/stt/value", editSample2Theta), + + t_tupEdit("net/mtheta", "nicos/mth/value", editMonoTheta), + t_tupEdit("net/m2theta", "nicos/mtt/value", editMono2Theta), + t_tupEdit("net/mono_d", "nicos/mono/dvalue", editMonoD), + + t_tupEdit("net/atheta", "nicos/ath/value", editAnaTheta), + t_tupEdit("net/a2theta", "nicos/att/value", editAna2Theta), + t_tupEdit("net/ana_d", "nicos/ana/dvalue", editAnaD), + + //t_tupEdit("net/stheta_aux", "nicos/sth/value", editRotTheta), + //t_tupEdit("net/stheta_aux_alias", "nicos/sth/alias", editRotAlias), + + t_tupEdit("gl/font", g_fontGL.toString().toStdString().c_str(), editGLFont), + t_tupEdit("main/font_gfx", g_fontGfx.toString().toStdString().c_str(), editGfxFont), + t_tupEdit("main/font_gen", g_fontGen.toString().toStdString().c_str(), editGenFont) + }; + + m_vecChecks = + { + t_tupCheck("main/dlg_previews", 1, checkPreview), + t_tupCheck("main/native_dialogs", 0, checkNativeDlg), + t_tupCheck("net/flip_orient2", 1, checkFlipOrient2), + }; + + m_vecSpins = + { + t_tupSpin("main/prec", g_iPrec, spinPrecGen), + t_tupSpin("main/prec_gfx", g_iPrecGfx, spinPrecGfx), + t_tupSpin("main/max_peaks", 10, spinBragg), + t_tupSpin("net/poll", 750, spinNetPoll), + }; + + m_vecCombos = + { + t_tupCombo("main/sfact_sq", 1, comboSFact), + }; + + spinPrecGen->setMaximum(std::numeric_limits::max_digits10); + spinPrecGfx->setMaximum(std::numeric_limits::max_digits10); + + SetDefaults(0); + + + if(m_pSettings && m_pSettings->contains("settings/geo")) + restoreGeometry(m_pSettings->value("settings/geo").toByteArray()); + + LoadSettings(); +} + +SettingsDlg::~SettingsDlg() +{} + + +void SettingsDlg::SetDefaults(bool bOverwrite) +{ + if(!m_pSettings) return; + + for(const t_tupEdit& tup : m_vecEdits) + { + const std::string& strKey = std::get<0>(tup); + const std::string& strDef = std::get<1>(tup); + + bool bKeyExists = m_pSettings->contains(strKey.c_str()); + if(bKeyExists && !bOverwrite) continue; + + m_pSettings->setValue(strKey.c_str(), strDef.c_str()); + } + + for(const t_tupCheck& tup : m_vecChecks) + { + const std::string& strKey = std::get<0>(tup); + const bool bDef = std::get<1>(tup); + + bool bKeyExists = m_pSettings->contains(strKey.c_str()); + if(bKeyExists && !bOverwrite) continue; + + m_pSettings->setValue(strKey.c_str(), bDef); + } + + for(const t_tupSpin& tup : m_vecSpins) + { + const std::string& strKey = std::get<0>(tup); + const int iDef = std::get<1>(tup); + + bool bKeyExists = m_pSettings->contains(strKey.c_str()); + if(bKeyExists && !bOverwrite) continue; + + m_pSettings->setValue(strKey.c_str(), iDef); + } + + for(const t_tupCombo& tup : m_vecCombos) + { + const std::string& strKey = std::get<0>(tup); + const int iDef = std::get<1>(tup); + + bool bKeyExists = m_pSettings->contains(strKey.c_str()); + if(bKeyExists && !bOverwrite) continue; + + m_pSettings->setValue(strKey.c_str(), iDef); + } +} + + +void SettingsDlg::LoadSettings() +{ + if(!m_pSettings) return; + + for(const t_tupEdit& tup : m_vecEdits) + { + const std::string& strKey = std::get<0>(tup); + const std::string& strDef = std::get<1>(tup); + QLineEdit* pEdit = std::get<2>(tup); + + QString strVal = m_pSettings->value(strKey.c_str(), strDef.c_str()).toString(); + pEdit->setText(strVal); + } + + for(const t_tupCheck& tup : m_vecChecks) + { + const std::string& strKey = std::get<0>(tup); + bool bDef = std::get<1>(tup); + QCheckBox* pCheck = std::get<2>(tup); + + bool bVal = m_pSettings->value(strKey.c_str(), bDef).toBool(); + pCheck->setChecked(bVal); + } + + for(const t_tupSpin& tup : m_vecSpins) + { + const std::string& strKey = std::get<0>(tup); + int iDef = std::get<1>(tup); + QSpinBox* pSpin = std::get<2>(tup); + + int iVal = m_pSettings->value(strKey.c_str(), iDef).toInt(); + pSpin->setValue(iVal); + } + + for(const t_tupCombo& tup : m_vecCombos) + { + const std::string& strKey = std::get<0>(tup); + int iDef = std::get<1>(tup); + QComboBox* pCombo = std::get<2>(tup); + + int iVal = m_pSettings->value(strKey.c_str(), iDef).toInt(); + pCombo->setCurrentIndex(iVal); + } + + SetGlobals(); +} + +void SettingsDlg::SaveSettings() +{ + if(!m_pSettings) return; + + for(const t_tupEdit& tup : m_vecEdits) + { + const std::string& strKey = std::get<0>(tup); + QLineEdit* pEdit = std::get<2>(tup); + + m_pSettings->setValue(strKey.c_str(), pEdit->text()); + } + + for(const t_tupCheck& tup : m_vecChecks) + { + const std::string& strKey = std::get<0>(tup); + QCheckBox* pCheck = std::get<2>(tup); + + m_pSettings->setValue(strKey.c_str(), pCheck->isChecked()); + } + + for(const t_tupSpin& tup : m_vecSpins) + { + const std::string& strKey = std::get<0>(tup); + QSpinBox* pSpin = std::get<2>(tup); + + m_pSettings->setValue(strKey.c_str(), pSpin->value()); + } + + for(const t_tupCombo& tup : m_vecCombos) + { + const std::string& strKey = std::get<0>(tup); + QComboBox* pCombo = std::get<2>(tup); + + m_pSettings->setValue(strKey.c_str(), pCombo->currentIndex()); + } + + SetGlobals(); +} + + +void SettingsDlg::SetGlobals() const +{ + // precisions + g_iPrec = spinPrecGen->value(); + g_iPrecGfx = spinPrecGfx->value(); + + g_dEps = std::pow(10., -t_real(g_iPrec)); + g_dEpsGfx = std::pow(10., -t_real(g_iPrecGfx)); + + g_bShowFsq = (comboSFact->currentIndex() == 1); + + // fonts + QString strGfxFont = editGfxFont->text(); + if(strGfxFont.length() != 0) + { + QFont font; + if(font.fromString(strGfxFont)) + g_fontGfx = font; + } + + QString strGLFont = editGLFont->text(); + if(strGLFont.length() != 0) + { + QFont font; + if(font.fromString(strGLFont)) + g_fontGL = font; + } + + QString strGenFont = editGenFont->text(); + if(strGenFont.length() != 0) + { + QFont font; + if(font.fromString(strGenFont)) + g_fontGen = font; + } + + emit SettingsChanged(); +} + + +void SettingsDlg::SelectGLFont() +{ + bool bOk; + QFont fontNew = QFontDialog::getFont(&bOk, g_fontGL, this); + if(bOk) + { + g_fontGL = fontNew; + editGLFont->setText(fontNew.toString()); + } +} + +void SettingsDlg::SelectGfxFont() +{ + bool bOk; + QFont fontNew = QFontDialog::getFont(&bOk, g_fontGfx, this); + if(bOk) + { + g_fontGfx = fontNew; + editGfxFont->setText(fontNew.toString()); + } +} + +void SettingsDlg::SelectGenFont() +{ + bool bOk; + QFont fontNew = QFontDialog::getFont(&bOk, g_fontGen, this); + if(bOk) + { + g_fontGen = fontNew; + editGenFont->setText(fontNew.toString()); + } +} + + +void SettingsDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + +void SettingsDlg::ButtonBoxClicked(QAbstractButton *pBtn) +{ + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ApplyRole || + buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + SaveSettings(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ResetRole) + { + SetDefaults(1); + LoadSettings(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::RejectRole) + { + QDialog::reject(); + } + + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + if(m_pSettings) + m_pSettings->setValue("settings/geo", saveGeometry()); + + QDialog::accept(); + } +} + +#include "SettingsDlg.moc" diff --git a/dialogs/SettingsDlg.h b/dialogs/SettingsDlg.h new file mode 100644 index 0000000..1c3f5f1 --- /dev/null +++ b/dialogs/SettingsDlg.h @@ -0,0 +1,66 @@ +/** + * Settings + * @author tweber + * @date 5-dec-2014 + * @license GPLv2 + */ + +#ifndef __TAZ_SETTINGS_H__ +#define __TAZ_SETTINGS_H__ + +#include +#include + +#include +#include +#include + +#include "ui/ui_settings.h" + + +class SettingsDlg : public QDialog, Ui::SettingsDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + + // key, default, lineedit + typedef std::tuple t_tupEdit; + std::vector m_vecEdits; + + // checkboxes + typedef std::tuple t_tupCheck; + std::vector m_vecChecks; + + // spins + typedef std::tuple t_tupSpin; + std::vector m_vecSpins; + + // combos + typedef std::tuple t_tupCombo; + std::vector m_vecCombos; + + public: + SettingsDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~SettingsDlg(); + + signals: + void SettingsChanged() const; + + protected: + void LoadSettings(); + void SaveSettings(); + + void SetDefaults(bool bOverwrite=0); + void SetGlobals() const; + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + + protected slots: + void ButtonBoxClicked(QAbstractButton* pBtn); + void SelectGLFont(); + void SelectGfxFont(); + void SelectGenFont(); +}; + +#endif diff --git a/dialogs/SpurionDlg.cpp b/dialogs/SpurionDlg.cpp new file mode 100644 index 0000000..8ee5dd3 --- /dev/null +++ b/dialogs/SpurionDlg.cpp @@ -0,0 +1,228 @@ +/* + * Spurion Dialog + * @author Tobias Weber + * @date 26-may-2014 + * @license GPLv2 + */ + +#include "SpurionDlg.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" + +#include +#include +#include + +using t_real = t_real_glob; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); + + +SpurionDlg::SpurionDlg(QWidget* pParent, QSettings *pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + m_plotwrap.reset(new QwtPlotWrapper(plotbragg)); + m_plotwrap->GetCurve(0)->setTitle("Bragg Tail"); + + if(m_plotwrap->HasTrackerSignal()) + connect(m_plotwrap->GetPicker(), SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); + + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::xBottom, "q (1/A)"); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::yLeft, "E (meV)"); + + + QObject::connect(radioFixedEi, SIGNAL(toggled(bool)), this, SLOT(ChangedKiKfMode())); + + QObject::connect(radioFixedEi, SIGNAL(toggled(bool)), this, SLOT(Calc())); + QObject::connect(btnSync, SIGNAL(toggled(bool)), this, SLOT(Calc())); + QObject::connect(spinE, SIGNAL(valueChanged(double)), this, SLOT(Calc())); + + QObject::connect(checkFilter, SIGNAL(toggled(bool)), this, SLOT(CalcInel())); + QObject::connect(spinOrder, SIGNAL(valueChanged(int)), this, SLOT(CalcInel())); + + QObject::connect(spinMinQ, SIGNAL(valueChanged(double)), this, SLOT(CalcBragg())); + QObject::connect(spinMaxQ, SIGNAL(valueChanged(double)), this, SLOT(CalcBragg())); + + Calc(); + + + if(m_pSettings && m_pSettings->contains("spurions/geo")) + restoreGeometry(m_pSettings->value("spurions/geo").toByteArray()); +} + +SpurionDlg::~SpurionDlg() +{} + + +void SpurionDlg::ChangedKiKfMode() +{ + if(radioFixedEi->isChecked()) + labelE->setText("E_i (meV):"); + else + labelE->setText("E_f (meV):"); +} + +void SpurionDlg::Calc() +{ + const bool bFixedEi = radioFixedEi->isChecked(); + + if(btnSync->isChecked()) + { + const t_real dSyncedE = bFixedEi ? m_dEi : m_dEf; + spinE->setValue(dSyncedE); + } + + CalcInel(); + CalcBragg(); +} + +void SpurionDlg::CalcInel() +{ + const bool bFixedEi = radioFixedEi->isChecked(); + t_real dE = spinE->value(); + + const unsigned int iMaxOrder = (unsigned int)spinOrder->value(); + const bool bFilter = checkFilter->isChecked(); + + std::vector vecSpurions; + std::vector vecInfo; + + if(bFilter) + { + for(unsigned int iOrder=1; iOrder<=iMaxOrder; ++iOrder) + { + unsigned int iOrderMono=1, iOrderAna=1; + if(bFixedEi) + iOrderAna = iOrder; + else + iOrderMono = iOrder; + + t_real dE_sp = tl::get_inelastic_spurion(bFixedEi, dE*meV, + iOrderMono, iOrderAna) / meV; + + if(dE_sp != 0.) + { + vecSpurions.push_back(dE_sp); + + std::ostringstream ostrInfo; + ostrInfo << "Mono order: " << iOrderMono + << ", Ana order: " << iOrderAna; + vecInfo.push_back(ostrInfo.str()); + } + } + } + else + { + for(unsigned int iOrderMono=1; iOrderMono<=iMaxOrder; ++iOrderMono) + for(unsigned int iOrderAna=1; iOrderAna<=iMaxOrder; ++iOrderAna) + { + t_real dE_sp = tl::get_inelastic_spurion(bFixedEi, dE*meV, + iOrderMono, iOrderAna) / meV; + + if(dE_sp != 0.) + { + vecSpurions.push_back(dE_sp); + + std::ostringstream ostrInfo; + ostrInfo << "Mono order: " << iOrderMono + << ", Ana order: " << iOrderAna; + vecInfo.push_back(ostrInfo.str()); + } + } + } + + const std::string& strDelta = tl::get_spec_char_utf8("Delta"); + const std::string& strBullet = tl::get_spec_char_utf8("bullet"); + + std::ostringstream ostr; + ostr << "Spurious inelastic signals for " + strDelta + "E = \n\n"; + for(unsigned int i=0; isetPlainText(QString::fromUtf8(ostr.str().c_str(), ostr.str().size())); +} + +void SpurionDlg::CalcBragg() +{ + const unsigned int NUM_POINTS = 512; + + const bool bFixedEi = radioFixedEi->isChecked(); + t_real dE = t_real(spinE->value()); + bool bImag; + tl::t_wavenumber_si k = tl::E2k(dE*meV, bImag); + + const t_real dMinq = spinMinQ->value(); + const t_real dMaxq = spinMaxQ->value(); + + m_vecQ = tl::linspace(dMinq, dMaxq, NUM_POINTS); + m_vecE.clear(); + m_vecE.reserve(m_vecQ.size()); + + for(t_real dq : m_vecQ) + { + tl::t_wavenumber_si q = dq/angs; + tl::t_energy_si E = tl::get_bragg_tail(k, q, bFixedEi); + + m_vecE.push_back(E/meV); + } + + set_qwt_data()(*m_plotwrap, m_vecQ, m_vecE); +} + +void SpurionDlg::cursorMoved(const QPointF& pt) +{ + std::string strX = tl::var_to_str(pt.x(), g_iPrecGfx); + std::string strY = tl::var_to_str(pt.y(), g_iPrecGfx); + + std::ostringstream ostr; + ostr << "(" << strX << ", " << strY << ")"; + + this->labelStatus->setText(ostr.str().c_str()); +} + + +void SpurionDlg::paramsChanged(const RecipParams& parms) +{ + tl::t_wavenumber_si ki = parms.dki / angs; + tl::t_wavenumber_si kf = parms.dkf / angs; + tl::t_energy_si Ei = tl::k2E(ki); + tl::t_energy_si Ef = tl::k2E(kf); + + m_dEi = Ei / meV; + m_dEf = Ef / meV; + + Calc(); +} + + +void SpurionDlg::accept() +{ + if(m_pSettings) + m_pSettings->setValue("spurions/geo", saveGeometry()); + + QDialog::accept(); +} + +void SpurionDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + + +#include "SpurionDlg.moc" diff --git a/dialogs/SpurionDlg.h b/dialogs/SpurionDlg.h new file mode 100644 index 0000000..3eba132 --- /dev/null +++ b/dialogs/SpurionDlg.h @@ -0,0 +1,50 @@ +/* + * Spurion Dialog + * @author Tobias Weber + * @date 26-may-2014 + * @license GPLv2 + */ + +#ifndef __SPURION_DLG_H__ +#define __SPURION_DLG_H__ + +#include +#include +#include +#include +#include "ui/ui_spurions.h" +#include "RecipParamDlg.h" +#include "libs/qthelper.h" +#include "libs/globals.h" + + +class SpurionDlg : public QDialog, Ui::SpurionDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + t_real_glob m_dEi=0., m_dEf=0.; + + std::vector m_vecQ, m_vecE; + std::unique_ptr m_plotwrap; + + public: + SpurionDlg(QWidget* pParent=0, QSettings *pSett=0); + virtual ~SpurionDlg(); + + protected slots: + void ChangedKiKfMode(); + void Calc(); + + void CalcInel(); + void CalcBragg(); + + void cursorMoved(const QPointF& pt); + void paramsChanged(const RecipParams& parms); + + protected: + virtual void showEvent(QShowEvent *pEvt) override; + virtual void accept() override; +}; + + +#endif diff --git a/dialogs/SrvDlg.cpp b/dialogs/SrvDlg.cpp new file mode 100644 index 0000000..ace7330 --- /dev/null +++ b/dialogs/SrvDlg.cpp @@ -0,0 +1,72 @@ +/* + * Server Dialog + * @author Tobias Weber + * @date 27-aug-2014 + * @license GPLv2 + */ + +#include "SrvDlg.h" +#include "tlibs/string/string.h" + +SrvDlg::SrvDlg(QWidget* pParent, QSettings *pSett) + : QDialog(pParent), m_pSettings(pSett) +{ + this->setupUi(this); + + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + + + bool bRememberPwd = 0; + if(m_pSettings->contains("server/remember_pwd")) + { + bRememberPwd = m_pSettings->value("server/remember_pwd").toBool(); + checkRememberPwd->setChecked(bRememberPwd); + } + if(m_pSettings->contains("server/login")) + editLogin->setText(m_pSettings->value("server/login").toString()); + if(bRememberPwd && m_pSettings->contains("server/pwd")) + editPwd->setText(m_pSettings->value("server/pwd").toString()); + + if(m_pSettings->contains("server/system")) + comboSys->setCurrentIndex(m_pSettings->value("server/system").toInt()); + if(m_pSettings->contains("server/host")) + editHost->setText(m_pSettings->value("server/host").toString()); + if(m_pSettings->contains("server/port")) + editPort->setText(m_pSettings->value("server/port").toString()); + } +} + +SrvDlg::~SrvDlg() +{} + +void SrvDlg::accept() +{ + const int iSys = comboSys->currentIndex(); + const QString strHost = editHost->text(); + const QString strPort = editPort->text(); + const QString strLogin = editLogin->text(); + const QString strPwd = editPwd->text(); + + if(m_pSettings) + { + m_pSettings->setValue("server/remember_pwd", checkRememberPwd->isChecked()); + m_pSettings->setValue("server/login", strLogin); + if(checkRememberPwd->isChecked()) + m_pSettings->setValue("server/pwd", strPwd); + else + m_pSettings->setValue("server/pwd", ""); + + m_pSettings->setValue("server/system", iSys); + m_pSettings->setValue("server/host", strHost); + m_pSettings->setValue("server/port", strPort); + } + + emit ConnectTo(iSys, strHost, strPort, strLogin, strPwd); + QDialog::accept(); +} + +#include "SrvDlg.moc" diff --git a/dialogs/SrvDlg.h b/dialogs/SrvDlg.h new file mode 100644 index 0000000..f27e8a7 --- /dev/null +++ b/dialogs/SrvDlg.h @@ -0,0 +1,32 @@ +/* + * Server Dialog + * @author Tobias Weber + * @date 27-aug-2014 + * @license GPLv2 + */ + +#ifndef __SRV_DLG_H__ +#define __SRV_DLG_H__ + +#include +#include +#include "ui/ui_connection.h" + +class SrvDlg : public QDialog, Ui::SrvDlg +{ Q_OBJECT + protected: + QSettings *m_pSettings = 0; + + public: + SrvDlg(QWidget* pParent=0, QSettings *pSett=0); + virtual ~SrvDlg(); + + signals: + void ConnectTo(int iSys, const QString& strHost, const QString& strPort, + const QString& strUser, const QString& strPass); + + protected: + virtual void accept() override; +}; + +#endif diff --git a/doc/basics.html b/doc/basics.html new file mode 100644 index 0000000..40f3c79 --- /dev/null +++ b/doc/basics.html @@ -0,0 +1,27 @@ + + + Basic Usage + + + +

Basic Usage

+ +

The main window is divided into two parts: The left-hand side is used for reciprocal-space visualisations: + The tab "Reciprocal Lattice" shows the Bragg peaks in the current scattering plane and the scattering + triangle, the tab "Projection" shows various projective views, e.g. for calculating Laue patterns. + + The right-hand side of the window depicts several real-space visualisations: Here, the real lattice and + the crystal's unit cell are shown (tab "Real Lattice") as well as the current instrumental position + for triple-axis spectrometers (tab "TAS Instrument") and for time-of-flight spectrometers + (tab "TOF Instrument").

+ +

The lattice constants and angles of the crystal's unit cell are entered in the lower-left part of the + Takin main window using either the "Real Lattice" or the "Recip. Lattice" tab. The tab "Recip. Plane" + defines the scattering plane used by the spectrometer.

+ +

If a spacegroup is defined (lower-central part of the main window), the forbidden reflexes are + excluded in the reciprocal-lattice view. Furthermore, the structure factor and the crystal's unit cell + are displayed if the atom positions are known: they can be entered using the "Atoms..." button.

+ + + diff --git a/doc/convo.html b/doc/convo.html new file mode 100644 index 0000000..a4529d7 --- /dev/null +++ b/doc/convo.html @@ -0,0 +1,31 @@ + + + Resolution Convolution + + + +

Resolution Convolution

+ +

In order to plan an experiment or to get an overview before using the more involved + convolution fitter, a live Monte-Carlo convolution can be performed by selecting + "Resolution" -> "Convolution..." in the menu bar.

+ +

In the "Convolution" dialog four things have to be defined: (1) a crystal, (2) an instrument, + (3) a theoretical model for the dynamical structure factor S(q,w), and (4) a scan direction:

+ +

(1) and (2): The crystal (together with a scattering plane) and the instrument parameter + files are entered in the "Crystal File" and "Resolution File" edit fields, respectively. + These files are the same ones that are defined in the Takin main window + and in the "Resolution Parameters" dialog.

+ +

(3): The S(q,w) model is a user-provided theoretical formula or algorithm for the physical + system to be measured. It can be either provided as a Python script + or as a plugin. + Several simple S(q,w) models are included internally.

+ +

(4): The actual scan path is defined in the "Scan Steps" group at the bottom of the dialog. + Here, the Q=(hkl) and E coordinates of the start end end position are entered along with the + number of subdivisions between these positions ("Steps").

+ + + diff --git a/doc/fit.html b/doc/fit.html new file mode 100644 index 0000000..df35b2e --- /dev/null +++ b/doc/fit.html @@ -0,0 +1,174 @@ + + + Convolution Fitting + + + +

Convolution Fitting

+ +

The convolution fitter finds the best least-squares fit of one or several + free parameters in an S(q,w) model using a Monte-Carlo convolution approach. + The S(q,w) model is fitted to one or more given measurement data files.

+ +

The fitter is called on the command-line by: "convofit my_fit.job" + The input job file "my_fit.job" in this example has the following structure:

+ +
+		; convofit sample job file
+
+		; input files
+		input
+		{
+		    ; file with the TAS scan
+		    scan_file       "my_measurement.dat"
+
+		    ; temperature column in the scan file
+		    temp_col        "Ts"
+
+		    ; field column in the scan file
+		    field_col        "Bs"
+
+		    ; counter column in the scan file
+		    counts_col      "ctr1"
+
+		    ; monitor counter column in the scan file
+		    monitor_col     "mon2"
+
+
+		    ; the instrument definition created by
+		    ; the Takin resolution parameter dialog
+		    instrument_file "my_instrument.taz"
+
+
+		    ; which S(q,w) model to use?
+		    sqw_model       "py"
+
+		    ; S(q,w) input file. Here, a Python script
+		    sqw_file        "my_sqw.py"
+
+		    ; how is the temperature/field variable named
+		    ; the S(q,w) model? Here, "g_T" and "g_H" are
+		    ; global variables in the "my_sqw.py" script.
+		    sqw_temp_var    "g_T"
+		    sqw_field_var   "g_H"
+
+		    ; fix some variables in the S(q,w) model
+		    sqw_set_params  "g_my_param = 12.3"
+		}
+
+
+		; output files
+		output
+		{
+		    ; a simplified copy of the original scan file for easier reading
+		    ; in an external plot program
+		    scan_file        "my_scan.dat"
+			
+		    ; a file describing the fit results
+		    model_file       "my_model.dat"
+
+		    ; logs
+		    log_file         "my_log.dat"
+
+
+		    ; show a plot at the end of the fit
+		    plot              1
+
+		    ; show plots during fitting (very useful for debugging)
+		    plot_intermediate 1
+		}
+
+
+		; includes a fit settings file (see below)
+		#include "my_settings.job"
+		
+ + + +
+ The fitting steps are described in the include file "my_settings.job" + which is given here: + +
+		; convofit sample fit settings file
+
+
+		; Monte-Carlo settings
+		montecarlo
+		{
+			; number of Monte-Carlo neutrons
+			neutrons    10000
+		}
+
+
+		; Resolution algo settings
+		resolution
+		{
+		    ; which algorithm to use?
+		    algorithm    "eck"    ; "cn", "pop", "eck", or "viol"
+
+		    ; include the "resolution volume" prefactor?
+		    use_r0       1
+
+		    ; use optimum vertical/horizontal monochromator/analyser focusing?
+		    focus_mono_v 1
+		    focus_mono_h 0
+		    focus_ana_v  0
+		    focus_ana_h  1
+		}
+
+
+		; Fitter settings
+		fitter
+		{
+		    ; do a convolution fit or just a plain convolution
+		    ; using the initial values?
+		    do_fit        1
+
+		    ; which minimiser to use?
+		    minimiser    "simplex"    ; "simplex" or "migrad"
+
+		    ; which Minuit strategy?
+		    strategy      1         ; 0 (low), 1 (medium) or 2 (high)
+
+		    ; number of maximum function calls
+		    max_funccalls 100
+
+		    ; Minuit's targeted "estimated distance to minimum"
+		    tolerance     10.
+
+		    sigma         1.
+		}
+
+
+		; which S(q,w) model parameters should be fitted?
+		; don't remove "scale" and "offs"!
+		fit_parameters
+		{
+		    ; the fit parameters: "scale" and "offs" are internal variables,
+		    ; "g_linewidth" is a parameter in the S(q,w) model. In this example,
+		    ; it is a global name in the "my_sqw.py" script.
+		    params  "scale " \
+		            "offs " \
+		            "g_linewidth "
+
+		    ; initial values of the three parameters
+		    values  "1e9 " \
+		            "1e-6 " \
+		            "0.02 "
+
+			; errors of the three parameters
+		    errors  "0.5e9 " \
+		            "0.5e-6 " \
+		            "0.01 "
+
+		    ; which parameters should be fitted?
+		    ; here, the third parameter, i.e. g_linewidth, is the only
+		    ; fit parameter
+		    fixed   "1 1 0 "
+		}
+		
+ + + + diff --git a/doc/index_help.html b/doc/index_help.html new file mode 100644 index 0000000..f70d996 --- /dev/null +++ b/doc/index_help.html @@ -0,0 +1,11 @@ + + + Takin Documentation + + + + + + + + diff --git a/doc/reso-sqw-native.html b/doc/reso-sqw-native.html new file mode 100644 index 0000000..447399f --- /dev/null +++ b/doc/reso-sqw-native.html @@ -0,0 +1,13 @@ + + + Native S(q,w) Models + + + +

Native S(q,w) Models

+ +

Takin can load S(q,w) plugins via native shared libraries (SO or DLL files). + A minimal example to build upon is given in the subdirectory "examples/sqw_module".

+ + + diff --git a/doc/reso-sqw-py.html b/doc/reso-sqw-py.html new file mode 100644 index 0000000..9dd258e --- /dev/null +++ b/doc/reso-sqw-py.html @@ -0,0 +1,41 @@ + + + Python S(q,w) Models + + + +

Python S(q,w) Models

+ +

A S(q,w) Python module has to define the two functions "TakinInit" and "TakinSqw".

+ +

"TakinInit" is called after one or several parameters have changed + (for example after each minimisation step in the convolution fitter). + It can be used to check if e.g. pre-calculated tables, variables, etc. need + to be recalculated.

+ +

The "TakinSqw" function receives four floating-point parameters h,k,l, and E + and returns a single floating-point value S, the dynamical structure factor. + The function is called for every Monte-Carlo point.

+ +

All global variables that are defined in an S(q,w) Python module are made + available as fit parameters for the convolution fitter.

+ + +

The interface is defined as follows (a full example can be found in the + subdirectory "examples/sqw_py"): + +

+	def TakinInit():
+	    # reinitialise variables here
+	    pass
+
+	def TakinSqw(h, k, l, E):
+	    S = 0.
+	    # calculate S here
+	    return S
+	

+ + + + + diff --git a/doc/reso-sqw.html b/doc/reso-sqw.html new file mode 100644 index 0000000..a516198 --- /dev/null +++ b/doc/reso-sqw.html @@ -0,0 +1,95 @@ + + + Internal S(q,w) Models + + + +

Internal S(q,w) Models

+ + Internal S(q,w) models include the following: + + +

Elastic Model

+

The elastic S(q,w) model consists of a list of elastic peaks which + are used to simulate Bragg tails. Each line defines a peak, with the + columns of each line being: h, k, l, q width, E width, and S.

+ +

Here's a sample input file defining three Bragg peaks: +

+		1 0 0    0.002 0.01    0.5
+		1 1 0    0.002 0.01    1
+		2 2 0    0.002 0.01    5
+		

+ + +

Tabulated Model

+

This model loads a table of S(Q,w) points in the four-dimensional (Q,E) + space and constructs a kd-tree out of it. As with the "elastic model" + each line defines one point. The columns are h, k, l, E, and S.

+ +

Here's a (very unrealistic) sample input file defining three points. + A realistic input file would include tens of thousands of points to cover + a fine and large enough grid in (Q,E) space. +

+		1 0 0    0    1
+		1 0 0  0.5    0.5
+		1 0 0 -0.5    0.5
+		

+ + +

Simple Phonon Model

+

With the simple phonon model sinusoidal phonon branches can be defined + around a given Bragg peak.

+ +

In the following input file we define a longitudinal [110] and two + transverse ([001] and [1-10]) branches around the (440) peak: + +

+		G               = 4,  4, 0
+		TA1             = 0,  0, 1
+		TA2             = 1, -1, 0
+
+		LA_amp          = 25
+		LA_freq         = 0.5*pi
+		LA_E_HWHM       = 0.1
+		LA_q_HWHM       = 0.05
+		LA_S0           = 1
+
+		TA1_amp         = 15
+		TA1_freq        = 0.5*pi/sqrt(2)
+		TA1_E_HWHM      = 0.2
+		TA1_q_HWHM      = 0.025
+		TA1_S0          = 1
+
+		TA2_amp         = 10
+		TA2_freq        = 0.5*pi/sqrt(2)
+		TA2_E_HWHM      = 0.2
+		TA2_q_HWHM      = 0.025
+		TA2_S0          = 1
+		

+ + + +

Simple Magnon Model

+

The simple magnon model creates quadratic (ferromagnetic) or linear (antiferromagnetic) + branches spherically around a given Bragg peak.

+ +

In the following input file we define magnons with a stiffness of D=20 around the + (110) peak: + +

+		disp            = 0
+		G               = 1,  1, 0
+
+		D               = 20
+		offs            = 0.
+		E_HWHM          = 0.05
+		q_HWHM          = 0.05
+		S0              = 1
+
+		num_points      = 50
+	

+ + + + diff --git a/doc/reso.html b/doc/reso.html new file mode 100644 index 0000000..ec61835 --- /dev/null +++ b/doc/reso.html @@ -0,0 +1,40 @@ + + + Resolution Calculation + + + +

Resolution Calculation

+

Set-up

+ +

For calculating the instrumental resolution at a given q=(hkl) and E position the instrumental parameters + have to be set-up first. This can be done using the option "Resolution" -> "Parameters..." in the menu + bar.

+ +

In the "Resolution Parameters" dialog box, an algorithm has to be set first. This is done in the + tab "Calculation". Depending on the selected algorithm various settings tabs will be enabled. + These contain -- among other things -- the geometrical description of the instrument.

+ +

Once all parameters are entered, a valid resolution matrix should be displayed in the "Calculation" + tab.

+ +

Instrument configurations can either be saved using the "Save..." button in the "Resolution Parameters" + dialog or via the menu bar in the Takin main window. The latter option saves the resolution settings + together with the crystal definition.

+ + +

Resolution Visualisation

+

Clicking on "Resolution" -> "Ellipses..." in the menu bar shows a live view of the resolution function + at the current instrument position. The blue (green) ellipse is a sliced (projected) view of the + four-dimensional ellipsoid using the given projection planes.

+ +

Visualisation of the resolution ellipses can be done in several coordinate systems that are selected + using the combo box at the bottom of the dialog: The first option shows the momentum transfers in inverse + Angstroms in the standard coordinate system with x along Q and y perpendicular to Q. The second + option chooses the crystal's rlu coordinate system with the h axis along x, k along y and l along + z. The third option also uses the crystal's rlu system, but with the x and y axis along the + Bragg reflexes chosen on the "Recip. Plane" tab in the Takin main window.

+ + + + diff --git a/doc/takin.html b/doc/takin.html new file mode 100644 index 0000000..dbfd8b1 --- /dev/null +++ b/doc/takin.html @@ -0,0 +1,19 @@ + + + Takin + + + +

Takin

+

An inelastic neutron scattering software package

+ + Takin is a software package for inelastic neutron scattering which features a full + GUI, but can also be used as a library. It can be employed for + lattice and scattering plane visualisation, triple-axis + and time-of-flight spectrometer resolution calculation, + planning of measurements using a live convolution preview, + and convolution fitting. + +

Contact + + diff --git a/doc/takin.qhcp b/doc/takin.qhcp new file mode 100644 index 0000000..daaf47a --- /dev/null +++ b/doc/takin.qhcp @@ -0,0 +1,30 @@ + + + + + + takin.qhp + takin.qch + + + + takin.qch + + + + + Takin + tobis_stuff/takin + + false + false + + qhelp://tobis_stuff.takin/help/takin.html + about:blank + + About Takin... + takin_info.txt + + + + diff --git a/doc/takin.qhp b/doc/takin.qhp new file mode 100644 index 0000000..0290683 --- /dev/null +++ b/doc/takin.qhp @@ -0,0 +1,31 @@ + + + tobis_stuff.takin + help + + + + +

+
+
+
+
+ +
+
+
+
+
+ + + + + + + *.html + + + + + diff --git a/doc/takin_info.txt b/doc/takin_info.txt new file mode 100644 index 0000000..ebdeb8c --- /dev/null +++ b/doc/takin_info.txt @@ -0,0 +1,6 @@ +Takin: +An inelastic neutron scattering software package. + +License: GPL version 2. +Author: Tobias Weber. +Date: 2014-2016. diff --git a/doc/toc.html b/doc/toc.html new file mode 100644 index 0000000..5cf4c10 --- /dev/null +++ b/doc/toc.html @@ -0,0 +1,21 @@ + + + Takin Documentation + + + + +

Contents

+ + Takin
+ Basic Usage
+ Resolution Calculation
+ Resolution Convolution
+ Convolution Fitting

+ Python S(q,w) Models
+ Native S(q,w) Models
+ Internal S(q,w) Models
+ + + + diff --git a/examples/sqw_module/sqwmod.cpp b/examples/sqw_module/sqwmod.cpp new file mode 100644 index 0000000..b2c8bcd --- /dev/null +++ b/examples/sqw_module/sqwmod.cpp @@ -0,0 +1,77 @@ +/** + * S(q,w) module example + * @author tweber + * @date 2016 + * @license GPLv2 + */ + +// gcc -I. -shared -fPIC -o sqwmod.so examples/sqw_module/sqwmod.cpp tools/monteconvo/sqwbase.cpp -std=c++11 -lstdc++ +#include "sqwmod.h" + +using t_real = t_real_reso; + + +SqwMod::SqwMod() +{ + SqwBase::m_bOk = 1; +} + +SqwMod::~SqwMod() +{ +} + +t_real SqwMod::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + return t_real(0); +} + +std::vector SqwMod::GetVars() const +{ + std::vector vec; + + return vec; +} + +void SqwMod::SetVars(const std::vector& vec) +{ +} + +bool SqwMod::SetVarIfAvail(const std::string& strKey, const std::string& strNewVal) +{ + return 0; +} + +SqwBase* SqwMod::shallow_copy() const +{ + return new SqwMod(); +} + + + +// ---------------------------------------------------------------------------- +// SO interface + +#include +#include +#include +#include +#include "libs/version.h" + +std::tuple sqw_info() +{ + std::cout << "In " << __func__ << "." << std::endl; + + return std::make_tuple(TAKIN_VER, "tstmod", "Test Module"); +} + +std::shared_ptr sqw_construct(const std::string& strCfgFile) +{ + std::cout << "In " << __func__ << "." << std::endl; + + return std::make_shared(); +} + + +// exports from so file +BOOST_DLL_ALIAS(sqw_info, takin_sqw_info); +BOOST_DLL_ALIAS(sqw_construct, takin_sqw); diff --git a/examples/sqw_module/sqwmod.h b/examples/sqw_module/sqwmod.h new file mode 100644 index 0000000..fd4663f --- /dev/null +++ b/examples/sqw_module/sqwmod.h @@ -0,0 +1,34 @@ +/** + * S(q,w) module example + * @author tweber + * @date 2016 + * @license GPLv2 + */ + +#ifndef __MCONV_SQW_MOD_H__ +#define __MCONV_SQW_MOD_H__ + +#include "../../tools/monteconvo/sqwbase.h" + + +class SqwMod : public SqwBase +{ + public: + using SqwBase::t_var; + + protected: + + public: + SqwMod(); + virtual ~SqwMod(); + + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + virtual bool SetVarIfAvail(const std::string& strKey, const std::string& strNewVal) override; + + virtual SqwBase* shallow_copy() const override; +}; + +#endif diff --git a/examples/sqw_py/sqw.py b/examples/sqw_py/sqw.py new file mode 100644 index 0000000..2767587 --- /dev/null +++ b/examples/sqw_py/sqw.py @@ -0,0 +1,100 @@ +# +# Sample Python S(q,w) module for (anti-)ferromagnetic dispersions +# @author tw +# @license GPLv2 +# @date jun-2016 +# + +import math as m + +import numpy as np +import numpy.linalg as la +from numpy import array # in global namespace so that Takin can access it + +import scipy as sp +import scipy.constants as const + + + +# ----------------------------------------------------------------------------- +# dispersion +# ----------------------------------------------------------------------------- + +# kB in meV/K +kB = const.k / const.e * 1e3 + + +# dispersion relations +def disp_ferro(q, D, offs): + return D*q**2. + offs + +def disp_antiferro(q, D, offs): + return D*q + offs + + +# Gaussian peak +def gauss(x, x0, sig, amp): + norm = (np.sqrt(2.*m.pi) * sig) + return amp * np.exp(-0.5*((x-x0)/sig)**2.) / norm + +# Bose factor +def bose(E, T): + if E >= 0.: + return 1./(m.exp(abs(E)/(kB*T)) - 1.) + 1.; + else: + return 1./(m.exp(abs(E)/(kB*T)) - 1.); + +# ----------------------------------------------------------------------------- + + + +# ----------------------------------------------------------------------------- +# Takin interface +# ----------------------------------------------------------------------------- + +# global variables which can be accessed / changed by Takin +g_G = np.array([1., 1., 0.]) # Bragg peak + +g_D = 20. # magnon stiffness +g_offs = 0. # energy gap +g_sig = 0.02 # linewidth +g_S0 = 1. # intensity + +g_inc_sig = 0.02 # incoherent width +g_inc_amp = 1. # incoherent intensity + +g_T = 300. # temperature + +g_disp = 0 # which dispersion? + + + +# the init function is called after Takin has changed a global variable +def TakinInit(): + print("Init: G=" + repr(g_G) + ", T=" + repr(g_T)) + + + +# called for every Monte-Carlo point +def TakinSqw(h, k, l, E): + try: + Q = np.array([h,k,l]) + q = la.norm(Q - g_G) + + E_peak = 0. + if g_disp == 0: + E_peak = disp_ferro(q, g_D, g_offs) + elif g_disp == 1: + E_peak = disp_antiferro(q, g_D, g_offs) + else: + return 0. + + S_p = gauss(E, E_peak, g_sig, g_S0) + S_m = gauss(E, -E_peak, g_sig, g_S0) + incoh = gauss(E, 0., g_inc_sig, g_inc_amp) + + return (S_p + S_m)*bose(E, g_T) + incoh + except ZeroDivisionError: + return 0. + +# ----------------------------------------------------------------------------- diff --git a/gentab b/gentab new file mode 120000 index 0000000..7d542da --- /dev/null +++ b/gentab @@ -0,0 +1 @@ +bin/gentab \ No newline at end of file diff --git a/lib/.dir b/lib/.dir new file mode 100644 index 0000000..92719a8 --- /dev/null +++ b/lib/.dir @@ -0,0 +1 @@ +directory for libraries diff --git a/libs/formfactors/formfact.cpp b/libs/formfactors/formfact.cpp new file mode 100644 index 0000000..94fe340 --- /dev/null +++ b/libs/formfactors/formfact.cpp @@ -0,0 +1,20 @@ +/* + * Form factor and scattering length tables + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#include "formfact.h" +#include "formfact_impl.h" +#include "libs/globals.h" + + +template class Formfact; +template class FormfactList; + +template class MagFormfact; +template class MagFormfactList; + +template class Scatlen; +template class ScatlenList; diff --git a/libs/formfactors/formfact.h b/libs/formfactors/formfact.h new file mode 100644 index 0000000..01b03c4 --- /dev/null +++ b/libs/formfactors/formfact.h @@ -0,0 +1,211 @@ +/* + * Form factor and scattering length tables + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_FFACT_H__ +#define __TAKIN_FFACT_H__ + +#include +#include +#include +#include + +#include "tlibs/helper/array.h" +#include "tlibs/math/atoms.h" +#include "tlibs/math/mag.h" +#include "libs/globals.h" + + +template +class Formfact +{ + template friend class FormfactList; + + public: + typedef T value_type; + + protected: + std::string strAtom; + + std::vector a; + std::vector b; + T c; + + public: + const std::string& GetAtomIdent() const { return strAtom; } + + T GetFormfact(T G) const + { + return tl::formfact(G, a, b, c); + } +}; + +template +class FormfactList +{ + public: + typedef Formfact elem_type; + typedef typename elem_type::value_type value_type; + + private: + static std::shared_ptr s_inst; + static std::mutex s_mutex; + + FormfactList(); + + protected: + std::vector s_vecAtoms, s_vecIons; + std::string s_strSrc, s_strSrcUrl; + + public: + virtual ~FormfactList(); + static std::shared_ptr GetInstance(); + + std::size_t GetNumAtoms() const { return s_vecAtoms.size(); } + const elem_type& GetAtom(std::size_t iFormfact) const + { return s_vecAtoms[iFormfact]; } + + std::size_t GetNumIons() const { return s_vecIons.size(); } + const elem_type& GetIon(std::size_t iFormfact) const + { return s_vecIons[iFormfact]; } + + const elem_type* Find(const std::string& strElem) const; + + const std::string& GetSource() const { return s_strSrc; } + const std::string& GetSourceUrl() const { return s_strSrcUrl; } +}; + + +// ---------------------------------------------------------------------------- + + +template +class MagFormfact +{ + template friend class MagFormfactList; + + public: + typedef T value_type; + + protected: + std::string strAtom; + std::vector A0, a0; + std::vector A2, a2; + + public: + const std::string& GetAtomIdent() const { return strAtom; } + + T GetFormfact(T Q, T L, T S, T J) const + { + return tl::mag_formfact + (Q, L,S,J, A0,a0, A2,a2); + } +}; + + +template +class MagFormfactList +{ + public: + typedef MagFormfact elem_type; + typedef typename elem_type::value_type value_type; + + private: + static std::shared_ptr s_inst; + static std::mutex s_mutex; + + MagFormfactList(); + + protected: + std::vector s_vecAtoms; + std::string s_strSrc, s_strSrcUrl; + + public: + virtual ~MagFormfactList(); + static std::shared_ptr GetInstance(); + + std::size_t GetNumAtoms() const { return s_vecAtoms.size(); } + const elem_type& GetAtom(std::size_t iFormfact) const + { return s_vecAtoms[iFormfact]; } + + const elem_type* Find(const std::string& strElem) const; + + const std::string& GetSource() const { return s_strSrc; } + const std::string& GetSourceUrl() const { return s_strSrcUrl; } +}; + + +// ---------------------------------------------------------------------------- + + +template> +class Scatlen +{ + template friend class ScatlenList; + + public: + typedef T value_type; + + protected: + std::string strAtom; + value_type coh; + value_type incoh; + + value_type xsec_coh; + value_type xsec_incoh; + value_type xsec_scat; + value_type xsec_abs; + + public: + const std::string& GetAtomIdent() const { return strAtom; } + + const value_type& GetCoherent() const { return coh; } + const value_type& GetIncoherent() const { return incoh; } + + const value_type& GetXSecCoherent() const { return xsec_coh; } + const value_type& GetXSecIncoherent() const { return xsec_incoh; } + const value_type& GetXSecScatter() const { return xsec_scat; } + const value_type& GetXSecAbsorption() const { return xsec_abs; } +}; + + +template +class ScatlenList +{ + public: + typedef Scatlen> elem_type; + typedef typename elem_type::value_type value_type; + + private: + static std::shared_ptr s_inst; + static std::mutex s_mutex; + + ScatlenList(); + + protected: + std::vector s_vecElems, s_vecIsotopes; + std::string s_strSrc, s_strSrcUrl; + + public: + virtual ~ScatlenList(); + static std::shared_ptr GetInstance(); + + std::size_t GetNumElems() const { return s_vecElems.size(); } + const elem_type& GetElem(std::size_t i) const + { return s_vecElems[i]; } + + std::size_t GetNumIsotopes() const { return s_vecIsotopes.size(); } + const elem_type& GetIsotope(std::size_t i) const + { return s_vecIsotopes[i]; } + + const elem_type* Find(const std::string& strElem) const; + + const std::string& GetSource() const { return s_strSrc; } + const std::string& GetSourceUrl() const { return s_strSrcUrl; } +}; + + +#endif diff --git a/libs/formfactors/formfact_impl.h b/libs/formfactors/formfact_impl.h new file mode 100644 index 0000000..8c59354 --- /dev/null +++ b/libs/formfactors/formfact_impl.h @@ -0,0 +1,302 @@ +/* + * Form factor and scattering length tables + * @author Tobias Weber + * @date nov-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_FFACT_IMPL_H__ +#define __TAKIN_FFACT_IMPL_H__ + +#include "formfact.h" +#include "libs/globals.h" +#include "tlibs/math/math.h" +#include "tlibs/log/log.h" +#include "tlibs/file/prop.h" +#include "tlibs/string/string.h" + + +template +std::shared_ptr> FormfactList::s_inst = nullptr; + +template +std::mutex FormfactList::s_mutex; + + +template +FormfactList::FormfactList() +{ + tl::log_debug("Loading atomic form factors."); + + tl::Prop xml; + if(!xml.Load(find_resource("res/ffacts.xml").c_str(), tl::PropType::XML)) + return; + + unsigned int iNumDat = xml.Query("ffacts/num_atoms", 0); + if(!iNumDat) + { + tl::log_err("No data in atomic form factor list."); + return; + } + + bool bIonStart = 0; + for(unsigned int iSf=0; iSf((strAtom + "/name").c_str(), ""); + tl::get_tokens> + (xml.Query((strAtom + "/a").c_str(), ""), " \t", ffact.a); + tl::get_tokens> + (xml.Query((strAtom + "/b").c_str(), ""), " \t", ffact.b); + ffact.c = xml.Query((strAtom + "/c").c_str(), 0.); + + if(!bIonStart && ffact.strAtom.find_first_of("+-") != std::string::npos) + bIonStart = 1; + + if(!bIonStart) + s_vecAtoms.push_back(std::move(ffact)); + else + s_vecIons.push_back(std::move(ffact)); + } + + s_strSrc = xml.Query("ffacts/source", ""); + s_strSrcUrl = xml.Query("ffacts/source_url", ""); +} + +template +FormfactList::~FormfactList() +{} + +template +std::shared_ptr> FormfactList::GetInstance() +{ + std::lock_guard _guard(s_mutex); + + if(!s_inst) + s_inst = std::shared_ptr>(new FormfactList()); + + return s_inst; +} + +template +const typename FormfactList::elem_type* FormfactList::Find(const std::string& strElem) const +{ + typedef typename decltype(s_vecAtoms)::const_iterator t_iter; + + // atoms + t_iter iter = std::find_if(s_vecAtoms.begin(), s_vecAtoms.end(), + [&strElem](const elem_type& elem)->bool + { + //std::cout << elem.GetAtomIdent() << std::endl; + return elem.GetAtomIdent() == strElem; + }); + if(iter != s_vecAtoms.end()) + return &*iter; + + // ions + iter = std::find_if(s_vecIons.begin(), s_vecIons.end(), + [&strElem](const elem_type& elem)->bool + { + //std::cout << elem.GetAtomIdent() << std::endl; + return elem.GetAtomIdent() == strElem; + }); + if(iter != s_vecIons.end()) + return &*iter; + + return nullptr; +} + + + + +// ============================================================================= + +template +std::shared_ptr> MagFormfactList::s_inst = nullptr; + +template +std::mutex MagFormfactList::s_mutex; + + +template +MagFormfactList::MagFormfactList() +{ + tl::log_debug("Loading magnetic form factors."); + + tl::Prop xml; + if(!xml.Load(find_resource("res/magffacts.xml").c_str(), tl::PropType::XML)) + return; + + unsigned int iNumDat = xml.Query("magffacts/num_atoms", 0); + if(!iNumDat) + { + tl::log_err("No data in magnetic form factor list."); + return; + } + for(unsigned int iSf=0; iSf((strAtom + "/name").c_str(), ""); + for(const std::string& strA : {"/A", "/B", "/C", "/D"}) + ffact.A0.push_back(xml.Query((strAtom + strA).c_str(), 0.)); + for(const std::string& stra : {"/a", "/b", "/c"}) + ffact.a0.push_back(xml.Query((strAtom + stra).c_str(), 0.)); + + s_vecAtoms.push_back(std::move(ffact)); + } + + for(unsigned int iSf=0; iSf((strAtom + "/name").c_str(), ""); + + MagFormfactList::elem_type* pElem = + const_cast::elem_type*>(Find(strAtomName)); + if(!pElem) + { + tl::log_err("Mismatch in j0 and j2 form factor tables."); + continue; + } + + for(const std::string& strA : {"/A", "/B", "/C", "/D"}) + pElem->A2.push_back(xml.Query((strAtom + strA).c_str(), 0.)); + for(const std::string& stra : {"/a", "/b", "/c"}) + pElem->a2.push_back(xml.Query((strAtom + stra).c_str(), 0.)); + } + + s_strSrc = xml.Query("magffacts/source", ""); + s_strSrcUrl = xml.Query("magffacts/source_url", ""); +} + +template +MagFormfactList::~MagFormfactList() +{} + +template +std::shared_ptr> MagFormfactList::GetInstance() +{ + std::lock_guard _guard(s_mutex); + + if(!s_inst) + s_inst = std::shared_ptr>(new MagFormfactList()); + + return s_inst; +} + +template +const typename MagFormfactList::elem_type* MagFormfactList::Find(const std::string& strElem) const +{ + typedef typename decltype(s_vecAtoms)::const_iterator t_iter; + + t_iter iter = std::find_if(s_vecAtoms.begin(), s_vecAtoms.end(), + [&strElem](const elem_type& elem) -> bool + { + return elem.GetAtomIdent() == strElem; + }); + if(iter != s_vecAtoms.end()) + return &*iter; + + return nullptr; +} + + + +// ============================================================================= + + +template +std::shared_ptr> ScatlenList::s_inst = nullptr; + +template +std::mutex ScatlenList::s_mutex; + + +template +ScatlenList::ScatlenList() +{ + tl::log_debug("Loading neutron scattering lengths."); + + tl::Prop xml; + if(!xml.Load(find_resource("res/scatlens.xml").c_str(), tl::PropType::XML)) + return; + + const unsigned int iNumDat = xml.Query("scatlens/num_atoms", 0); + if(!iNumDat) + { + tl::log_err("No data in scattering length list."); + return; + } + + for(unsigned int iSl=0; iSl::elem_type slen; + std::string strAtom = "scatlens/atom_" + tl::var_to_str(iSl); + + slen.strAtom = xml.Query((strAtom + "/name").c_str(), ""); + slen.coh = xml.Query::value_type>((strAtom + "/coh").c_str(), 0.); + slen.incoh = xml.Query::value_type>((strAtom + "/incoh").c_str(), 0.); + + slen.xsec_coh = xml.Query::value_type>((strAtom + "/xsec_coh").c_str(), 0.); + slen.xsec_incoh = xml.Query::value_type>((strAtom + "/xsec_incoh").c_str(), 0.); + slen.xsec_scat = xml.Query::value_type>((strAtom + "/xsec_scat").c_str(), 0.); + slen.xsec_abs = xml.Query::value_type>((strAtom + "/xsec_abs").c_str(), 0.); + + + if(std::isdigit(slen.strAtom[0])) + s_vecIsotopes.push_back(std::move(slen)); + else + s_vecElems.push_back(std::move(slen)); + } + + s_strSrc = xml.Query("scatlens/source", ""); + s_strSrcUrl = xml.Query("scatlens/source_url", ""); +} + +template +ScatlenList::~ScatlenList() +{} + +template +std::shared_ptr> ScatlenList::GetInstance() +{ + std::lock_guard _guard(s_mutex); + + if(!s_inst) + s_inst = std::shared_ptr>(new ScatlenList()); + + return s_inst; +} + +template +const typename ScatlenList::elem_type* ScatlenList::Find(const std::string& strElem) const +{ + typedef typename decltype(s_vecElems)::const_iterator t_iter; + + // elements + t_iter iter = std::find_if(s_vecElems.begin(), s_vecElems.end(), + [&strElem](const elem_type& elem)->bool + { + //std::cout << elem.GetAtomIdent() << std::endl; + return elem.GetAtomIdent() == strElem; + }); + if(iter != s_vecElems.end()) + return &*iter; + + // isotopes + iter = std::find_if(s_vecIsotopes.begin(), s_vecIsotopes.end(), + [&strElem](const elem_type& elem)->bool + { + //std::cout << elem.GetAtomIdent() << std::endl; + return elem.GetAtomIdent() == strElem; + }); + if(iter != s_vecIsotopes.end()) + return &*iter; + + return nullptr; +} + +#endif diff --git a/libs/globals.cpp b/libs/globals.cpp new file mode 100644 index 0000000..62b0824 --- /dev/null +++ b/libs/globals.cpp @@ -0,0 +1,76 @@ +/** + * globals + * @author tweber + * @date 20-mar-2015 + * @license GPLv2 + */ + +#include "globals.h" +#include "tlibs/log/log.h" +#include "tlibs/file/file.h" + + +// ----------------------------------------------------------------------------- + +unsigned int g_iPrec = 6; +unsigned int g_iPrecGfx = 4; + +t_real_glob g_dEps = 1e-6; +t_real_glob g_dEpsGfx = 1e-4; + +bool g_bHasFormfacts = 0; +bool g_bHasMagFormfacts = 0; +bool g_bHasScatlens = 0; +bool g_bHasSpaceGroups = 0; +bool g_bShowFsq = 1; + + +// ----------------------------------------------------------------------------- + + +static std::vector s_vecInstallPaths = +{ + ".", +#ifdef INSTALL_PREFIX + INSTALL_PREFIX "/share/takin", +#endif +}; + + +void add_resource_path(const std::string& strPath) +{ + s_vecInstallPaths.push_back(strPath); +} + +std::string find_resource(const std::string& strFile) +{ + for(const std::string& strPrefix : s_vecInstallPaths) + { + std::string _strFile = strPrefix + "/" + strFile; + //tl::log_debug("Looking for file: ", _strFile); + if(tl::file_exists(_strFile.c_str())) + return _strFile; + else if(tl::file_exists((_strFile + ".gz").c_str())) + return _strFile + ".gz"; + else if(tl::file_exists((_strFile + ".bz2").c_str())) + return _strFile + ".bz2"; + } + + tl::log_err("Could not load resource file \"", strFile, "\"."); + return ""; +} + +std::string find_resource_dir(const std::string& strDir) +{ + for(const std::string& strPrefix : s_vecInstallPaths) + { + std::string _strDir = strPrefix + "/" + strDir; + if(tl::dir_exists(_strDir.c_str())) + return _strDir; + } + + tl::log_err("Could not load resource directory \"", strDir, "\"."); + return ""; +} + +// ----------------------------------------------------------------------------- diff --git a/libs/globals.h b/libs/globals.h new file mode 100644 index 0000000..d478dae --- /dev/null +++ b/libs/globals.h @@ -0,0 +1,35 @@ +/** + * globals + * @author tweber + * @date 20-mar-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_GLOBALS_H__ +#define __TAKIN_GLOBALS_H__ + +#include + + +//using t_real_glob = float; +using t_real_glob = double; + + +extern unsigned int g_iPrec; +extern unsigned int g_iPrecGfx; + +extern t_real_glob g_dEps; +extern t_real_glob g_dEpsGfx; + +extern bool g_bHasFormfacts; +extern bool g_bHasMagFormfacts; +extern bool g_bHasScatlens; +extern bool g_bHasSpaceGroups; +extern bool g_bShowFsq; + +extern void add_resource_path(const std::string& strPath); +extern std::string find_resource(const std::string& strFile); +extern std::string find_resource_dir(const std::string& strDir); + + +#endif diff --git a/libs/globals_qt.cpp b/libs/globals_qt.cpp new file mode 100644 index 0000000..b27cbe7 --- /dev/null +++ b/libs/globals_qt.cpp @@ -0,0 +1,26 @@ +/** + * globals + * @author tweber + * @date 20-mar-2015 + * @license GPLv2 + */ + +#include "globals.h" +#include "globals_qt.h" +#include "tlibs/log/log.h" +#include "tlibs/file/file.h" + + +QFont g_fontGen("DejaVu Sans",10); +QFont g_fontGfx("DejaVu Sans",10); +QFont g_fontGL("DejaVu Sans Mono",10); + + +QIcon load_icon(const std::string& strIcon) +{ + std::string strFile = find_resource(strIcon); + if(strFile != "") + return QIcon(strFile.c_str()); + + return QIcon(); +} diff --git a/libs/globals_qt.h b/libs/globals_qt.h new file mode 100644 index 0000000..7ca5b8d --- /dev/null +++ b/libs/globals_qt.h @@ -0,0 +1,20 @@ +/* + * globals + * @author tweber + * @date 20-mar-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_GLOBALS_QT_H__ +#define __TAKIN_GLOBALS_QT_H__ + +#include + +#include +#include + +extern QIcon load_icon(const std::string& strIcon); +extern QFont g_fontGen, g_fontGfx, g_fontGL; + + +#endif diff --git a/libs/plotgl.cpp b/libs/plotgl.cpp new file mode 100644 index 0000000..36d4ed3 --- /dev/null +++ b/libs/plotgl.cpp @@ -0,0 +1,638 @@ +/* + * gl plotter + * @author tweber + * @date 19-may-2013 + * @license GPLv2 + */ + +#include "plotgl.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/math.h" +#include "tlibs/string/string.h" +#include "tlibs/helper/flags.h" + +#include +#include +#include +#include + +// TODO: make fully generic +using t_real = t_real_glob; + + +#if QT_VER>=5 + #define POS_F localPos +#else + #define POS_F posF +#endif + + +PlotGl::PlotGl(QWidget* pParent, QSettings *pSettings) + : QGLWidget(pParent), m_pSettings(pSettings), m_bEnabled(true), + m_mutex(QMutex::Recursive), + m_matProj(tl::unit_matrix(4)), m_matView(tl::unit_matrix(4)) +{ + m_dMouseRot[0] = m_dMouseRot[1] = 0.; + m_dMouseScale = 25.; + updateViewMatrix(); + + setAutoBufferSwap(false); + //setUpdatesEnabled(0); + doneCurrent(); + start(); // render thread +} + +PlotGl::~PlotGl() +{ + m_bRenderThreadActive = 0; + wait(250); + terminate(); +} + +void PlotGl::SetEnabled(bool b) +{ + m_bEnabled.store(b); +} + +void PlotGl::SetColor(t_real r, t_real g, t_real b, t_real a) +{ + GLfloat pfCol[] = {GLfloat(r), GLfloat(g), GLfloat(b), GLfloat(a)}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, pfCol); +} + +void PlotGl::SetColor(unsigned int iIdx) +{ + static const GLfloat cols[4][4] = + { + { 0., 0., 1., 0.7 }, + { 0., 0.5, 0., 0.7 }, + { 1., 0., 0., 0.7 }, + { 0., 0., 0., 0.7 } + }; + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cols[iIdx % 4]); +} + +void PlotGl::initializeGLThread() +{ + glClearColor(1.,1.,1.,0.); + glShadeModel(GL_SMOOTH); + + glDisable(GL_DEPTH_TEST); + //glEnable(GL_DEPTH_TEST); + glClearDepth(1.); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); + + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + + GLfloat vecLightCol[] = { 1., 1., 1., 1. }; + glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, vecLightCol); + + unsigned int iLOD = 32; + for(unsigned iSphere=0; iSphere= 5 + // TODO: get selected font path + m_pFont = new tl::GlFontMap(DEF_FONT, g_fontGL.pointSize()); +#else + m_pFont = new tl::GlFontMap(g_fontGL.freetypeFace()); +#endif + +#if QT_VER>=5 + QWidget:: +#endif + setMouseTracking(1); +} + +void PlotGl::freeGLThread() +{ +#if QT_VER>=5 + QWidget:: +#endif + setMouseTracking(0); + + for(unsigned iSphere=0; iSphere _lck(m_mutex); + tl::to_gl_array(m_matView, glmat); + } + glLoadMatrixd(glmat); + + + glPushMatrix(); + glDisable(GL_LIGHTING); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glLineWidth(2.); + glColor3d(0., 0., 0.); + + const double dAxisScale = 1.8; + glBegin(GL_LINES); + glVertex3d(m_dXMin*dAxisScale, 0., 0.); + glVertex3d(m_dXMax*dAxisScale, 0., 0.); + glVertex3d(0., m_dYMin*dAxisScale, 0.); + glVertex3d(0., m_dYMax*dAxisScale, 0.); + glVertex3d(0., 0., m_dZMin*dAxisScale); + glVertex3d(0., 0., m_dZMax*dAxisScale); + glEnd(); + glPopMatrix(); + + glEnable(GL_BLEND); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glDisable(GL_TEXTURE_2D); + + std::unique_lock _lck(m_mutex); + unsigned int iPltIdx=0; + for(const PlotObjGl& obj : m_vecObjs) + { + int iLOD = 0; + + bool bColorSet = 0; + if(obj.bSelected) + { + SetColor(0.25, 0.25, 0.25, 0.9); + bColorSet = 1; + } + + glPushMatrix(); + if(obj.plttype == PLOT_SPHERE) + { + glTranslated(obj.vecParams[0], obj.vecParams[1], obj.vecParams[2]); + glScaled(obj.vecParams[3], obj.vecParams[3], obj.vecParams[3]); + } + else if(obj.plttype == PLOT_ELLIPSOID) + { + glTranslated(obj.vecParams[3], obj.vecParams[4], obj.vecParams[5]); + + GLdouble dMatRot[] = {obj.vecParams[6], obj.vecParams[7], obj.vecParams[8], 0., + obj.vecParams[9], obj.vecParams[10], obj.vecParams[11], 0., + obj.vecParams[12], obj.vecParams[13], obj.vecParams[14], 0., + 0., 0., 0., 1. }; + glMultMatrixd(dMatRot); + glScaled(obj.vecParams[0], obj.vecParams[1], obj.vecParams[2]); + } + else + tl::log_warn("Unknown plot object."); + + if(obj.bUseLOD) + { + double dLenDist = tl::gl_proj_sphere_size(/*dRadius*/1.); + //std::cout << "proj sphere size: " << dLenDist << std::endl; + iLOD = dLenDist * 50.; + if(iLOD >= int(sizeof(m_iLstSphere)/sizeof(*m_iLstSphere))) + iLOD = sizeof(m_iLstSphere)/sizeof(*m_iLstSphere)-1; + if(iLOD < 0) iLOD = 0; + iLOD = sizeof(m_iLstSphere)/sizeof(*m_iLstSphere) - iLOD - 1; + //std::cout << "dist: " << dLenDist << ", lod: " << iLOD << std::endl; + } + + if(!bColorSet) + { + if(obj.vecColor.size()) + SetColor(obj.vecColor[0], obj.vecColor[1], obj.vecColor[2], obj.vecColor[3]); + else + SetColor(iPltIdx); + } + glCallList(m_iLstSphere[iLOD]); + + if(obj.bSelected && obj.strLabel.length() && m_pFont && m_pFont->IsOk()) + { + glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT); + m_pFont->BindTexture(); + glColor4d(0., 0., 0., 1.); + m_pFont->DrawText(0., 0., 0., obj.strLabel); + glPopAttrib(); + } + + glPopMatrix(); + + ++iPltIdx; + } + _lck.unlock(); + + glPushMatrix(); + if(m_pFont && m_pFont->IsOk()) + { + m_pFont->BindTexture(); + + glColor4d(0., 0., 1., 1.); + m_pFont->DrawText(m_dXMax*dAxisScale, 0., 0., m_strLabels[0].toStdString()); + m_pFont->DrawText(0., m_dYMax*dAxisScale , 0., m_strLabels[1].toStdString()); + m_pFont->DrawText(0., 0., m_dZMax*dAxisScale , m_strLabels[2].toStdString()); + + glColor4d(0., 0., 0., 1.); + m_pFont->DrawText(m_dXMin, 0., 0., tl::var_to_str(m_dXMin+m_dXMinMaxOffs, m_iPrec)); + m_pFont->DrawText(m_dXMax, 0., 0., tl::var_to_str(m_dXMax+m_dXMinMaxOffs, m_iPrec)); + m_pFont->DrawText(0., m_dYMin, 0., tl::var_to_str(m_dYMin+m_dYMinMaxOffs, m_iPrec)); + m_pFont->DrawText(0., m_dYMax, 0., tl::var_to_str(m_dYMax+m_dYMinMaxOffs, m_iPrec)); + m_pFont->DrawText(0., 0., m_dZMin, tl::var_to_str(m_dZMin+m_dZMinMaxOffs, m_iPrec)); + m_pFont->DrawText(0., 0., m_dZMax, tl::var_to_str(m_dZMax+m_dZMinMaxOffs, m_iPrec)); + } + glPopMatrix(); + + swapBuffers(); +} + +void PlotGl::run() +{ + makeCurrent(); + initializeGLThread(); + + double dTime = 0.; + while(m_bRenderThreadActive) + { + if(m_bDoResize) + { + std::lock_guard _lck(m_mutex); + resizeGLThread(m_iW, m_iH); + m_bDoResize = 0; + } + + if(isVisible()) + { + tickThread(dTime); + paintGLThread(); + } + + timespec ts; + long fps = isVisible() ? 30 : 3; + ts.tv_nsec = 1000000000 / fps; + ts.tv_sec = 0; + dTime += double(ts.tv_nsec) * 1e-9; + nanosleep(&ts, 0); + } + + freeGLThread(); + //log_info("gl thread ended."); +} + +void PlotGl::paintEvent(QPaintEvent *evt) +{} + +void PlotGl::resizeEvent(QResizeEvent *evt) +{ + std::lock_guard _lck(m_mutex); + + m_iW = size().width(); + m_iH = size().height(); + + m_bDoResize = 1; +} + +void PlotGl::clear() +{ + std::lock_guard _lck(m_mutex); + m_vecObjs.clear(); +} + +void PlotGl::SetObjectColor(int iObjIdx, const std::vector& vecCol) +{ + std::lock_guard _lck(m_mutex); + + if(m_vecObjs.size() <= (unsigned int)iObjIdx || iObjIdx<0) + return; + m_vecObjs[iObjIdx].vecColor = vecCol; +} + +void PlotGl::SetObjectLabel(int iObjIdx, const std::string& strLab) +{ + std::lock_guard _lck(m_mutex); + + if(m_vecObjs.size() <= (unsigned int)iObjIdx || iObjIdx<0) + return; + m_vecObjs[iObjIdx].strLabel = strLab; +} + +void PlotGl::SetObjectUseLOD(int iObjIdx, bool bLOD) +{ + std::lock_guard _lck(m_mutex); + + if(m_vecObjs.size() <= (unsigned int)iObjIdx || iObjIdx<0) + return; + m_vecObjs[iObjIdx].bUseLOD = bLOD; +} + +void PlotGl::PlotSphere(const ublas::vector& vecPos, + double dRadius, int iObjIdx) +{ + if(iObjIdx < 0) + { + clear(); + iObjIdx = 0; + } + + { + std::lock_guard _lck(m_mutex); + + if(iObjIdx >= int(m_vecObjs.size())) + m_vecObjs.resize(iObjIdx+1); + PlotObjGl& obj = m_vecObjs[iObjIdx]; + + obj.plttype = PLOT_SPHERE; + if(obj.vecParams.size() != 4) + obj.vecParams.resize(4); + + obj.vecParams[0] = vecPos[0]; + obj.vecParams[1] = vecPos[1]; + obj.vecParams[2] = vecPos[2]; + obj.vecParams[3] = dRadius; + } +} + +void PlotGl::PlotEllipsoid(const ublas::vector& widths, + const ublas::vector& offsets, + const ublas::matrix& rot, + int iObjIdx) +{ + if(iObjIdx < 0) + { + clear(); + iObjIdx = 0; + } + + { + std::lock_guard _lck(m_mutex); + + if(iObjIdx >= int(m_vecObjs.size())) + m_vecObjs.resize(iObjIdx+1); + PlotObjGl& obj = m_vecObjs[iObjIdx]; + + obj.plttype = PLOT_ELLIPSOID; + if(obj.vecParams.size() != 15) + obj.vecParams.resize(15); + + obj.vecParams[0] = widths[0]; + obj.vecParams[1] = widths[1]; + obj.vecParams[2] = widths[2]; + obj.vecParams[3] = offsets[0]; + obj.vecParams[4] = offsets[1]; + obj.vecParams[5] = offsets[2]; + + unsigned int iNum = 6; + for(unsigned int i=0; i<3; ++i) + for(unsigned int j=0; j<3; ++j) + obj.vecParams[iNum++] = rot(j,i); + } +} + +void PlotGl::mousePressEvent(QMouseEvent *event) +{ + if(event->buttons() & Qt::RightButton) + { + m_bMouseRotateActive = 1; + + m_dMouseBegin[0] = event->POS_F().x(); + m_dMouseBegin[1] = event->POS_F().y(); + } + + if(event->buttons() & Qt::LeftButton) + { + m_bMouseScaleActive = 1; + m_dMouseScaleBegin = event->POS_F().y(); + } +} + +void PlotGl::mouseReleaseEvent(QMouseEvent *event) +{ + if((event->buttons() & Qt::RightButton) == 0) + m_bMouseRotateActive = 0; + + if((event->buttons() & Qt::LeftButton) == 0) + m_bMouseScaleActive = 0; +} + +void PlotGl::mouseMoveEvent(QMouseEvent *pEvt) +{ + bool bUpdateView = 0; + if(m_bMouseRotateActive) + { + double dNewX = pEvt->POS_F().x(); + double dNewY = pEvt->POS_F().y(); + + m_dMouseRot[0] += dNewX - m_dMouseBegin[0]; + m_dMouseRot[1] += dNewY - m_dMouseBegin[1]; + + m_dMouseBegin[0] = dNewX; + m_dMouseBegin[1] = dNewY; + + bUpdateView = 1; + } + + if(m_bMouseScaleActive) + { + double dNewY = pEvt->POS_F().y(); + + m_dMouseScale *= 1.-(dNewY - m_dMouseScaleBegin)/double(height()) * 2.; + m_dMouseScaleBegin = dNewY; + + bUpdateView = 1; + } + + if(bUpdateView) + updateViewMatrix(); + + + + m_dMouseX = 2.*pEvt->POS_F().x()/double(m_iW) - 1.; + m_dMouseY = -(2.*pEvt->POS_F().y()/double(m_iH) - 1.); + //std::cout << m_dMouseX << ", " << m_dMouseY << std::endl; + + bool bEnabled = m_bEnabled.load(); + if(bEnabled) + mouseSelectObj(m_dMouseX, m_dMouseY); +} + +void PlotGl::updateViewMatrix() +{ + tl::t_mat4 matScale = tl::make_mat( + {{m_dMouseScale, 0, 0, 0}, + { 0, m_dMouseScale, 0, 0}, + { 0, 0, m_dMouseScale, 0}, + { 0, 0, 0, 1}}); + + tl::t_mat4 matR0 = tl::rotation_matrix_3d_z(tl::d2r(m_dMouseRot[0])); + tl::t_mat4 matR1 = tl::rotation_matrix_3d_x(tl::d2r(-90. + m_dMouseRot[1])); + matR0.resize(4,4,1); matR1.resize(4,4,1); + matR0(3,3) = matR1(3,3) = 1.; + for(short i=0; i<3; ++i) matR0(i,3)=matR0(3,i)=matR1(i,3)=matR1(3,i)=0.; + tl::t_mat4 matRot0 = matR0, matRot1 = matR1; + + tl::t_mat4 matTrans = tl::make_mat( + {{ 1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 1, -2}, + { 0, 0, 0, 1}}); + + { + std::lock_guard _lck(m_mutex); + m_matView = ublas::prod(matTrans, matRot1); + m_matView = ublas::prod(m_matView, matRot0); + m_matView = ublas::prod(m_matView, matScale); + } +} + +void PlotGl::mouseSelectObj(double dX, double dY) +{ + std::lock_guard _lck(m_mutex); + tl::Line ray = tl::screen_ray(dX, dY, m_matProj, m_matView); + + for(PlotObjGl& obj : m_vecObjs) + { + obj.bSelected = 0; + + tl::Quadric *pQuad = nullptr; + tl::t_vec3 vecOffs = ublas::zero_vector(3); + + if(obj.plttype == PLOT_SPHERE) + { + pQuad = new tl::QuadSphere(obj.vecParams[3]); + vecOffs = tl::make_vec({obj.vecParams[0], obj.vecParams[1], obj.vecParams[2]}); + } + else if(obj.plttype == PLOT_ELLIPSOID) + { + pQuad = new tl::QuadEllipsoid(obj.vecParams[0], obj.vecParams[1], obj.vecParams[2]); + + vecOffs = tl::make_vec({obj.vecParams[3], obj.vecParams[4], obj.vecParams[5]}); + tl::t_mat3 matRot = tl::make_mat( + {{obj.vecParams[6], obj.vecParams[7], obj.vecParams[8]}, + {obj.vecParams[9], obj.vecParams[10], obj.vecParams[11]}, + {obj.vecParams[12], obj.vecParams[13], obj.vecParams[14]}}); + pQuad->transform(matRot); + } + + pQuad->SetOffset(vecOffs); + + std::vector vecT = pQuad->intersect(ray); + if(vecT.size() > 0) + { + for(double t : vecT) + { + if(t < 0.) continue; // beyond "near" plane + if(t > 1.) continue; // beyond "far" plane + obj.bSelected = 1; + } + } + + delete pQuad; + } +} + +void PlotGl::SetLabels(const char* pcLabX, const char* pcLabY, const char* pcLabZ) +{ + std::lock_guard _lck(m_mutex); + + m_strLabels[0] = pcLabX; + m_strLabels[1] = pcLabY; + m_strLabels[2] = pcLabZ; +} + + + +/* +// gcc -std=c++11 -I/usr/include/freetype2 -o tst_gl helper/plotgl.cpp helper/log.cpp helper/gl.cpp -lm -lstdc++ -lQtGui -lQtCore -lQtOpenGL -lGL -lGLU -lX11 -lfreetype + +#include +#include +#include + +extern "C" int XInitThreads(); +int main(int argc, char **argv) +{ + //QuadSphere sph(1.23); + //sph.SetOffset(make_vec({0.,0.,0.})); + //Line line(make_vec({0.,0.,0.0}), make_vec({0.,0.,1.})); + //std::vector vec = sph.intersect(line); + //for(double d : vec) + // std::cout << d << ", "; + //std::cout << std::endl; + + XInitThreads(); + QApplication a(argc, argv); + + QDialog dlg; + PlotGl *pGl = new PlotGl(&dlg); + + pGl->SetObjectCount(3); + pGl->PlotSphere(make_vec({0., 0.5, -0.5}), 0.2, 0); + pGl->SetObjectColor(0, {1., 0., 0., 0.5}); + + pGl->PlotSphere(make_vec({0., 0., -2.}), 0.4, 1); + pGl->SetObjectColor(1, {0., 0., 1., 0.5}); + + pGl->PlotEllipsoid(make_vec({0.1, 0.2, 0.3}), + make_vec({0., 0.5, 0.}), + make_mat({{1.,0.,0.},{0.,1.,0.},{0.,0.,1.}}), 2); + pGl->SetObjectColor(2, {0., 1., 0., 0.5}); + + pGl->SetMinMax(make_vec({-1.,-1.,-1.}), make_vec({1.,1.,1.})); + + dlg.resize(640,480); + QGridLayout *pGrid = new QGridLayout(&dlg); + pGrid->addWidget(pGl, 0,0,1,1); + dlg.exec(); + + delete pGl; + return 0; +} +*/ diff --git a/libs/plotgl.h b/libs/plotgl.h new file mode 100644 index 0000000..0791928 --- /dev/null +++ b/libs/plotgl.h @@ -0,0 +1,159 @@ +/* + * gl plotter + * @author tweber + * @date 19-may-2013 + * @license GPLv2 + */ + +#ifndef __MIEZE_PLOT_GL__ +#define __MIEZE_PLOT_GL__ + +#if QT_VER>=5 + #include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "tlibs/gfx/gl.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" + +#include +#include +namespace ublas = boost::numeric::ublas; + + +enum PlotTypeGl +{ + PLOT_INVALID, + + PLOT_SPHERE, + PLOT_ELLIPSOID, +}; + +struct PlotObjGl +{ + PlotTypeGl plttype = PLOT_INVALID; + std::vector vecParams; + std::vector vecColor; + + bool bSelected = 0; + bool bUseLOD = 1; + std::string strLabel; +}; + +class PlotGl : public QGLWidget, QThread +{ +protected: + QSettings *m_pSettings = 0; + std::atomic m_bEnabled; + QMutex m_mutex; + + static constexpr double m_dFOV = 45./180.*M_PI; + tl::t_mat4 m_matProj, m_matView; + + tl::GlFontMap *m_pFont = nullptr; + + std::vector m_vecObjs; + GLuint m_iLstSphere[8]; + QString m_strLabels[3]; + + unsigned int m_iPrec = 6; + double m_dXMin=-10., m_dXMax=10.; + double m_dYMin=-10., m_dYMax=10.; + double m_dZMin=-10., m_dZMax=10.; + double m_dXMinMaxOffs, m_dYMinMaxOffs, m_dZMinMaxOffs; + + //void initializeGL(); + void resizeEvent(QResizeEvent*); + void paintEvent(QPaintEvent*); + + void SetColor(t_real_glob r, t_real_glob g, t_real_glob b, t_real_glob a=1.); + void SetColor(unsigned int iIdx); + + // ------------------------------------------------------------------------ + // mouse stuff + bool m_bMouseRotateActive = 0; + double m_dMouseRot[2]; + double m_dMouseBegin[2]; + + bool m_bMouseScaleActive = 0; + double m_dMouseScale; + double m_dMouseScaleBegin; + + double m_dMouseX = 0., m_dMouseY = 0.; + + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + + void updateViewMatrix(); + void mouseSelectObj(double dX, double dY); + + // ------------------------------------------------------------------------ + // render thread + bool m_bGLInited = 0; + bool m_bDoResize = 1; + bool m_bRenderThreadActive = 1; + + void initializeGLThread(); + void freeGLThread(); + void resizeGLThread(int w, int h); + void paintGLThread(); + void tickThread(double dTime); + void run(); + + int m_iW=640, m_iH=480; + // ------------------------------------------------------------------------ + +public: + PlotGl(QWidget* pParent, QSettings *pSettings=0); + virtual ~PlotGl(); + + void PlotSphere(const ublas::vector& vecPos, double dRadius, int iObjIdx=-1); + void PlotEllipsoid(const ublas::vector& widths, + const ublas::vector& offsets, + const ublas::matrix& rot, + int iObjsIdx=-1); + void SetObjectCount(unsigned int iSize) { m_vecObjs.resize(iSize); } + void SetObjectColor(int iObjIdx, const std::vector& vecCol); + void SetObjectLabel(int iObjIdx, const std::string& strLab); + void SetObjectUseLOD(int iObjIdx, bool bLOD); + void clear(); + + void SetLabels(const char* pcLabX, const char* pcLabY, const char* pcLabZ); + + template + void SetMinMax(const t_vec& vecMin, const t_vec& vecMax, const t_vec* pOffs=0) + { + m_dXMin = vecMin[0]; m_dXMax = vecMax[0]; + m_dYMin = vecMin[1]; m_dYMax = vecMax[1]; + m_dZMin = vecMin[2]; m_dZMax = vecMax[2]; + + m_dXMinMaxOffs = pOffs ? (*pOffs)[0] : 0.; + m_dYMinMaxOffs = pOffs ? (*pOffs)[1] : 0.; + m_dZMinMaxOffs = pOffs ? (*pOffs)[2] : 0.; + } + + template > + void SetMinMax(const t_vec& vec, const t_vec* pOffs=0) + { + m_dXMin = -vec[0]; m_dXMax = vec[0]; + m_dYMin = -vec[1]; m_dYMax = vec[1]; + m_dZMin = -vec[2]; m_dZMax = vec[2]; + + m_dXMinMaxOffs = pOffs ? (*pOffs)[0] : 0.; + m_dYMinMaxOffs = pOffs ? (*pOffs)[1] : 0.; + m_dZMinMaxOffs = pOffs ? (*pOffs)[2] : 0.; + } + + void SetEnabled(bool b); + void SetPrec(unsigned int iPrec) { m_iPrec = iPrec; } +}; + +#endif diff --git a/libs/qthelper.cpp b/libs/qthelper.cpp new file mode 100644 index 0000000..422ab1f --- /dev/null +++ b/libs/qthelper.cpp @@ -0,0 +1,393 @@ +/* + * qt&qwt helpers + * @author Tobias Weber + * @date feb-2016 + * @license GPLv2 + */ + +#include "qthelper.h" +#include "globals.h" +#include "globals_qt.h" +#include "tlibs/math/math.h" +#include "tlibs/string/string.h" + +#include +#include +//#include +#include +#include + +#include +#include + +#include +#include +#include + + +class MyQwtPlotZoomer : public QwtPlotZoomer +{ +protected: + virtual void widgetMouseReleaseEvent(QMouseEvent *pEvt) override + { + // filter out middle button event which is already used for panning + if(pEvt->button() & Qt::MiddleButton) + return; + + QwtPlotZoomer::widgetMouseReleaseEvent(pEvt); + } + +public: + template + explicit MyQwtPlotZoomer(t_widget_or_canvas* ptr) : QwtPlotZoomer(ptr) + { + QwtPlotZoomer::setMaxStackDepth(-1); + QwtPlotZoomer::setEnabled(1); + } + + virtual ~MyQwtPlotZoomer() {} +}; + + +// ---------------------------------------------------------------------------- + + +class MyQwtPlotPicker : public QwtPlotPicker +{ +protected: + QwtPlotWrapper *m_pPlotWrap = nullptr; + + virtual void widgetKeyPressEvent(QKeyEvent *pEvt) override + { + const int iKey = pEvt->key(); + //std::cout << "Plot key: " << iKey << std::endl; + if(iKey == Qt::Key_S) + m_pPlotWrap->SavePlot(); + else + QwtPlotPicker::widgetKeyPressEvent(pEvt); + } + +public: + MyQwtPlotPicker(QwtPlotWrapper *pPlotWrap, bool bNoTrackerSignal=0) : + QwtPlotPicker(pPlotWrap->GetPlot()->xBottom, pPlotWrap->GetPlot()->yLeft, +#if QWT_VER<6 + QwtPlotPicker::PointSelection, +#endif + QwtPlotPicker::NoRubberBand, + bNoTrackerSignal ? QwtPicker::AlwaysOn : QwtPicker::AlwaysOff, + pPlotWrap->GetPlot()->canvas()), + m_pPlotWrap(pPlotWrap) + { +#if QWT_VER>=6 + QwtPlotPicker::setStateMachine(new QwtPickerTrackerMachine()); + //connect(this, SIGNAL(moved(const QPointF&)), this, SLOT(cursorMoved(const QPointF&))); +#endif + QwtPlotPicker::setEnabled(1); + } + + virtual ~MyQwtPlotPicker() {} +}; + + +// ---------------------------------------------------------------------------- + + +QwtPlotWrapper::QwtPlotWrapper(QwtPlot *pPlot, + unsigned int iNumCurves, bool bNoTrackerSignal) + : m_pPlot(pPlot) +{ + QPen penGrid; + penGrid.setColor(QColor(0x99,0x99,0x99)); + penGrid.setStyle(Qt::DashLine); + + QPen penCurve; + penCurve.setColor(QColor(0,0,0x99)); + penCurve.setWidth(2); + + QColor colorBck(240, 240, 240, 255); + m_pPlot->setCanvasBackground(colorBck); + + m_vecCurves.reserve(iNumCurves); + for(unsigned int iCurve=0; iCurvesetPen(penCurve); + pCurve->setRenderHint(QwtPlotItem::RenderAntialiased, true); + pCurve->attach(m_pPlot); + m_vecCurves.push_back(pCurve); + } + + m_pGrid = new QwtPlotGrid(); + m_pGrid->setPen(penGrid); + m_pGrid->attach(m_pPlot); + + + m_pPanner = new QwtPlotPanner(m_pPlot->canvas()); + m_pPanner->setMouseButton(Qt::MiddleButton); + + +#if QWT_VER>=6 + m_pZoomer = new MyQwtPlotZoomer(m_pPlot->canvas()); +#else + // display tracker overlay anyway + if(bNoTrackerSignal==0) bNoTrackerSignal = 1; +#endif + + + m_pPicker = new MyQwtPlotPicker(this, bNoTrackerSignal); + m_pPlot->canvas()->setMouseTracking(1); + + + // fonts + QwtText txt = m_pPlot->title(); + txt.setFont(g_fontGfx); + m_pPlot->setTitle(txt); + for(QwtPlot::Axis ax : {QwtPlot::yLeft, QwtPlot::yRight, QwtPlot::xBottom, QwtPlot::xTop}) + { + txt = m_pPlot->axisTitle(ax); + txt.setFont(g_fontGfx); + m_pPlot->setAxisTitle(ax, txt); + } +} + + +QwtPlotWrapper::~QwtPlotWrapper() +{ + if(m_pPicker) + { + m_pPicker->setEnabled(0); + delete m_pPicker; + m_pPicker = nullptr; + } + if(m_pGrid) + { + delete m_pGrid; + m_pGrid = nullptr; + } + if(m_pZoomer) + { + delete m_pZoomer; + m_pZoomer = nullptr; + } + if(m_pPanner) + { + delete m_pPanner; + m_pPanner = nullptr; + } +} + + +#if QWT_VER>=6 + bool QwtPlotWrapper::HasTrackerSignal() const { return 1; } +#else + bool QwtPlotWrapper::HasTrackerSignal() const { return 0; } +#endif + + +void QwtPlotWrapper::SetData(const std::vector& vecX, const std::vector& vecY, + unsigned int iCurve, bool bReplot, bool bCopy) +{ + if(!bCopy) // copy pointers + { +#if QWT_VER>=6 + m_vecCurves[iCurve]->setRawSamples(vecX.data(), vecY.data(), std::min(vecX.size(), vecY.size())); +#else + m_vecCurves[iCurve]->setRawData(vecX.data(), vecY.data(), std::min(vecX.size(), vecY.size())); +#endif + + m_bHasDataPtrs = 1; + if(iCurve >= m_vecDataPtrs.size()) + m_vecDataPtrs.resize(iCurve+1); + + m_vecDataPtrs[iCurve].first = &vecX; + m_vecDataPtrs[iCurve].second = &vecY; + } + else // copy data + { +#if QWT_VER>=6 + m_vecCurves[iCurve]->setSamples(vecX.data(), vecY.data(), std::min(vecX.size(), vecY.size())); +#else + m_vecCurves[iCurve]->setData(vecX.data(), vecY.data(), std::min(vecX.size(), vecY.size())); +#endif + + m_bHasDataPtrs = 0; + m_vecDataPtrs.clear(); + } + + if(bReplot) + { + set_zoomer_base(m_pZoomer, vecX, vecY); + m_pPlot->replot(); + } +} + + +void QwtPlotWrapper::SavePlot() const +{ + if(!m_bHasDataPtrs) + { + // if data was deep-copied, it is now lost somewhere in the plot objects... + QMessageBox::critical(m_pPlot, "Error", "Cannot get plot data."); + return; + } + + QFileDialog::Option fileopt = QFileDialog::Option(0); + //if(!m_settings.value("main/native_dialogs", 1).toBool()) + // fileopt = QFileDialog::DontUseNativeDialog; + + std::string strFile = QFileDialog::getSaveFileName(m_pPlot, + "Save Plot Data", nullptr, "Data files (*.dat *.DAT)", + nullptr, fileopt).toStdString(); + + tl::trim(strFile); + if(strFile == "") + return; + + std::ofstream ofstrDat(strFile); + if(!ofstrDat) + { + std::string strErr = "Cannot open file \"" + strFile + "\" for saving."; + QMessageBox::critical(m_pPlot, "Error", strErr.c_str()); + return; + } + + ofstrDat.precision(g_iPrec); + ofstrDat << "# title: " << m_pPlot->title().text().toStdString() << "\n"; + ofstrDat << "# x_label: " << m_pPlot->axisTitle(QwtPlot::xBottom).text().toStdString() << "\n"; + ofstrDat << "# y_label: " << m_pPlot->axisTitle(QwtPlot::yLeft).text().toStdString() << "\n"; + ofstrDat << "# x_label_2: " << m_pPlot->axisTitle(QwtPlot::xTop).text().toStdString() << "\n"; + ofstrDat << "# y_label_2: " << m_pPlot->axisTitle(QwtPlot::yRight).text().toStdString() << "\n"; + ofstrDat << "\n"; + + std::size_t iDataSet=0; + for(const auto& pairVecs : m_vecDataPtrs) + { + if(m_vecDataPtrs.size() > 1) + ofstrDat << "## -------------------------------- begin of dataset " << (iDataSet+1) + << " --------------------------------\n"; + + const std::vector* pVecX = pairVecs.first; + const std::vector* pVecY = pairVecs.second; + + const std::size_t iSize = std::min(pVecX->size(), pVecY->size()); + + for(std::size_t iCur=0; iCuroperator[](iCur) << " "; + ofstrDat << std::left << std::setw(g_iPrec*2) << pVecY->operator[](iCur) << "\n"; + } + + if(m_vecDataPtrs.size() > 1) + ofstrDat << "## -------------------------------- end of dataset " << (iDataSet+1) + << " ----------------------------------\n\n"; + ++iDataSet; + } +} + +// ---------------------------------------------------------------------------- + + +bool save_table(const char* pcFile, const QTableWidget* pTable) +{ + std::ofstream ofstr(pcFile); + if(!ofstr) + return false; + + const int iNumCols = pTable->columnCount(); + const int iNumRows = pTable->rowCount(); + + // item lengths + std::unique_ptr ptrMaxTxtLen(new int[iNumCols]); + for(int iCol=0; iColhorizontalHeaderItem(iCol); + ptrMaxTxtLen[iCol] = std::max(pItem ? pItem->text().length() : 0, ptrMaxTxtLen[iCol]); + } + + for(int iRow=0; iRowitem(iRow, iCol); + ptrMaxTxtLen[iCol] = std::max(pItem ? pItem->text().length() : 0, ptrMaxTxtLen[iCol]); + } + + + // write items + for(int iCol=0; iColhorizontalHeaderItem(iCol); + ofstr << std::setw(ptrMaxTxtLen[iCol]+4) << (pItem ? pItem->text().toStdString() : ""); + } + ofstr << "\n"; + + for(int iRow=0; iRowitem(iRow, iCol); + ofstr << std::setw(ptrMaxTxtLen[iCol]+4) << (pItem ? pItem->text().toStdString() : ""); + } + + ofstr << "\n"; + } + + return true; +} + + +// ---------------------------------------------------------------------------- + + +void set_zoomer_base(QwtPlotZoomer *pZoomer, + const std::vector& vecX, const std::vector& vecY, + bool bMetaCall) +{ + if(!pZoomer) + return; + + const auto minmaxX = std::minmax_element(vecX.begin(), vecX.end()); + const auto minmaxY = std::minmax_element(vecY.begin(), vecY.end()); + //tl::log_debug("min: ", *minmaxX.first, " ", *minmaxY.first); + //tl::log_debug("max: ", *minmaxX.second, " ", *minmaxY.second); + + t_real_qwt dminmax[] = {*minmaxX.first, *minmaxX.second, + *minmaxY.first, *minmaxY.second}; + + if(tl::float_equal(dminmax[0], dminmax[1])) + { + dminmax[0] -= dminmax[0]/10.; + dminmax[1] += dminmax[1]/10.; + } + if(tl::float_equal(dminmax[2], dminmax[3])) + { + dminmax[2] -= dminmax[2]/10.; + dminmax[3] += dminmax[3]/10.; + } + + QRectF rect; + rect.setLeft(dminmax[0]); + rect.setRight(dminmax[1]); + rect.setTop(dminmax[2]); + rect.setBottom(dminmax[3]); + + if(bMetaCall) + { + QMetaObject::invokeMethod(pZoomer, "zoom", + Qt::ConnectionType::DirectConnection, + Q_ARG(QRectF, rect)); + // unfortunately not a metafunction... + //QMetaObject::invokeMethod(pZoomer, "setZoomBase", + // Qt::ConnectionType::DirectConnection, + // Q_ARG(QRectF, rect)); + } + else + { + pZoomer->zoom(rect); + pZoomer->setZoomBase(rect); + } +} + +// ---------------------------------------------------------------------------- diff --git a/libs/qthelper.h b/libs/qthelper.h new file mode 100644 index 0000000..fb24f3e --- /dev/null +++ b/libs/qthelper.h @@ -0,0 +1,165 @@ +/* + * qt&qwt helpers + * @author Tobias Weber + * @date feb-2016 + * @license GPLv2 + */ + +#ifndef __QT_HELPER_H__ +#define __QT_HELPER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tlibs/string/string.h" + + +using t_real_qwt = double; // qwt's intrinsic value type + + +class QwtPlotWrapper +{ +protected: + QwtPlot *m_pPlot = nullptr; + std::vector m_vecCurves; + QwtPlotGrid *m_pGrid = nullptr; + QwtPlotPicker *m_pPicker = nullptr; + QwtPlotZoomer *m_pZoomer = nullptr; + QwtPlotPanner *m_pPanner = nullptr; + + bool m_bHasDataPtrs = 1; + std::vector*, const std::vector*>> m_vecDataPtrs; + +public: + QwtPlotWrapper(QwtPlot *pPlot, unsigned int iNumCurves=1, bool bNoTrackerSignal=0); + virtual ~QwtPlotWrapper(); + + QwtPlot* GetPlot() { return m_pPlot; } + QwtPlotCurve* GetCurve(unsigned int iCurve=0) { return m_vecCurves[iCurve]; } + QwtPlotZoomer* GetZoomer() { return m_pZoomer; } + QwtPlotPicker* GetPicker() { return m_pPicker; } + bool HasTrackerSignal() const; + + void SetData(const std::vector& vecX, const std::vector& vecY, + unsigned int iCurve=0, bool bReplot=1, bool bCopy=0); + + void SavePlot() const; +}; + + +// ---------------------------------------------------------------------------- + +template::value> +struct set_qwt_data +{ + void operator()(QwtPlotWrapper& plot, const std::vector& vecX, const std::vector& vecY, + unsigned int iCurve=0, bool bReplot=1) {} +}; + +// same types -> set data directly +template +struct set_qwt_data +{ + void operator()(QwtPlotWrapper& plot, const std::vector& vecX, const std::vector& vecY, + unsigned int iCurve=0, bool bReplot=1) + { + plot.SetData(vecX, vecY, iCurve, bReplot, 0); + } +}; + +// different types -> copy & convert data first +template +struct set_qwt_data +{ + void operator()(QwtPlotWrapper& plot, const std::vector& vecX, const std::vector& vecY, + unsigned int iCurve=0, bool bReplot=1) + { + std::vector vecNewX, vecNewY; + vecNewX.reserve(vecX.size()); + vecNewY.reserve(vecY.size()); + + for(t_real d : vecX) vecNewX.push_back(d); + for(t_real d : vecY) vecNewY.push_back(d); + + plot.SetData(vecNewX, vecNewY, iCurve, bReplot, 1); + } +}; + +// ---------------------------------------------------------------------------- + + +extern bool save_table(const char* pcFile, const QTableWidget* pTable); + +extern void set_zoomer_base(QwtPlotZoomer *pZoomer, + const std::vector& vecX, const std::vector& vecY, + bool bMetaCall=false); + + +// ---------------------------------------------------------------------------- + + +// a table widget item with a stored numeric value +template +class QTableWidgetItemWrapper : public QTableWidgetItem +{ +protected: + T m_tVal; + unsigned int m_iPrec = std::numeric_limits::digits10; + +public: + QTableWidgetItemWrapper() : QTableWidgetItem(), m_tVal() + {} + // same value and item text + QTableWidgetItemWrapper(T tVal) + : QTableWidgetItem(tl::var_to_str(tVal, std::numeric_limits::digits10).c_str()), + m_tVal(tVal) + {} + // one value, but different text + QTableWidgetItemWrapper(T tVal, const std::string& strText) + : QTableWidgetItem(strText.c_str()), + m_tVal(tVal) + {} + + virtual ~QTableWidgetItemWrapper() = default; + + unsigned int GetPrec() const { return m_iPrec; } + void SetPrec(unsigned int iPrec) { m_iPrec = iPrec; } + + T GetValue() const { return m_tVal; } + + // same value and item text + void SetValue(T val) + { + m_tVal = val; + this->setText(tl::var_to_str(m_tVal, m_iPrec).c_str()); + } + // one value, but different text + void SetValue(T val, const std::string& str) + { + m_tVal = val; + this->setText(str.c_str()); + } + void SetValueKeepText(T val) + { + m_tVal = val; + } + + virtual bool operator<(const QTableWidgetItem& item) const override + { + const QTableWidgetItemWrapper* pItem = + dynamic_cast*>(&item); + if(!pItem) return 0; + + return this->GetValue() < pItem->GetValue(); + } +}; + + +#endif diff --git a/libs/spacegroups/crystalsys.cpp b/libs/spacegroups/crystalsys.cpp new file mode 100644 index 0000000..43e22e9 --- /dev/null +++ b/libs/spacegroups/crystalsys.cpp @@ -0,0 +1,226 @@ +/* + * Crystal Systems + * @author Tobias Weber + * @date oct-2015 + * @license GPLv2 + */ + +#include "crystalsys.h" +#include "tlibs/string/string.h" + +CrystalSystem get_crystal_system_from_laue_group(const char* pcLaue) +{ + std::string strLaue = pcLaue; + tl::trim(strLaue); + + if(strLaue == "-1") + return CRYS_TRICLINIC; + else if(strLaue == "2/m") + return CRYS_MONOCLINIC; + else if(strLaue == "mmm") + return CRYS_ORTHORHOMBIC; + else if(strLaue == "4/m" || strLaue == "4/mmm") + return CRYS_TETRAGONAL; + else if(strLaue == "-3" || strLaue == "-3m") + return CRYS_TRIGONAL; + else if(strLaue == "6/m" || strLaue == "6/mmm") + return CRYS_HEXAGONAL; + else if(strLaue == "m-3" || strLaue == "m-3m") + return CRYS_CUBIC; + + return CRYS_NOT_SET; +} + +const char* get_crystal_system_name(CrystalSystem ty) +{ + switch(ty) + { + case CRYS_NOT_SET: return ""; + case CRYS_TRICLINIC: return "triclinic"; + case CRYS_MONOCLINIC: return "monoclinic"; + case CRYS_ORTHORHOMBIC: return "orthorhombic"; + case CRYS_TETRAGONAL: return "tetragonal"; + case CRYS_TRIGONAL: return "trigonal"; + case CRYS_HEXAGONAL: return "hexagonal"; + case CRYS_CUBIC: return "cubic"; + } + + return ""; +} + +#ifndef NO_QT + +void set_crystal_system_edits(CrystalSystem crystalsys, + QLineEdit* editA, QLineEdit* editB, QLineEdit* editC, + QLineEdit* editAlpha, QLineEdit* editBeta, QLineEdit* editGamma, + QLineEdit* editARecip, QLineEdit* editBRecip, QLineEdit* editCRecip, + QLineEdit* editAlphaRecip, QLineEdit* editBetaRecip, QLineEdit* editGammaRecip) +{ + switch(crystalsys) + { + case CRYS_CUBIC: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(0); + if(editC) editC->setEnabled(0); + if(editAlpha) editAlpha->setEnabled(0); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(0); + if(editCRecip) editCRecip->setEnabled(0); + if(editAlphaRecip) editAlphaRecip->setEnabled(0); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editB) editB->setText(editA->text()); + if(editC) editC->setText(editA->text()); + if(editBRecip) editBRecip->setText(editARecip->text()); + if(editCRecip) editCRecip->setText(editARecip->text()); + if(editAlpha) editAlpha->setText("90"); + if(editBeta) editBeta->setText("90"); + if(editGamma) editGamma->setText("90"); + if(editAlphaRecip) editAlphaRecip->setText("90"); + if(editBetaRecip) editBetaRecip->setText("90"); + if(editGammaRecip) editGammaRecip->setText("90"); + break; + + case CRYS_HEXAGONAL: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(0); + if(editC) editC->setEnabled(1); + if(editAlpha) editAlpha->setEnabled(0); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(0); + if(editCRecip) editCRecip->setEnabled(1); + if(editAlphaRecip) editAlphaRecip->setEnabled(0); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editB) editB->setText(editA->text()); + if(editBRecip) editBRecip->setText(editARecip->text()); + if(editAlpha) editAlpha->setText("90"); + if(editBeta) editBeta->setText("90"); + if(editGamma) editGamma->setText("120"); + if(editAlphaRecip) editAlphaRecip->setText("90"); + if(editBetaRecip) editBetaRecip->setText("90"); + if(editGammaRecip) editGammaRecip->setText("60"); + break; + + case CRYS_MONOCLINIC: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(1); + if(editC) editC->setEnabled(1); + if(editAlpha) editAlpha->setEnabled(1); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(1); + if(editCRecip) editCRecip->setEnabled(1); + if(editAlphaRecip) editAlphaRecip->setEnabled(1); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editBeta) editBeta->setText("90"); + if(editGamma) editGamma->setText("90"); + if(editBetaRecip) editBetaRecip->setText("90"); + if(editGammaRecip) editGammaRecip->setText("90"); + break; + + case CRYS_ORTHORHOMBIC: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(1); + if(editC) editC->setEnabled(1); + if(editAlpha) editAlpha->setEnabled(0); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(1); + if(editCRecip) editCRecip->setEnabled(1); + if(editAlphaRecip) editAlphaRecip->setEnabled(0); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editAlpha) editAlpha->setText("90"); + if(editBeta) editBeta->setText("90"); + if(editGamma) editGamma->setText("90"); + if(editAlphaRecip) editAlphaRecip->setText("90"); + if(editBetaRecip) editBetaRecip->setText("90"); + if(editGammaRecip) editGammaRecip->setText("90"); + break; + + case CRYS_TETRAGONAL: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(0); + if(editC) editC->setEnabled(1); + if(editAlpha) editAlpha->setEnabled(0); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(0); + if(editCRecip) editCRecip->setEnabled(1); + if(editAlphaRecip) editAlphaRecip->setEnabled(0); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editB) editB->setText(editA->text()); + if(editBRecip) editBRecip->setText(editARecip->text()); + if(editAlpha) editAlpha->setText("90"); + if(editBeta) editBeta->setText("90"); + if(editGamma) editGamma->setText("90"); + if(editAlphaRecip) editAlphaRecip->setText("90"); + if(editBetaRecip) editBetaRecip->setText("90"); + if(editGammaRecip) editGammaRecip->setText("90"); + break; + + case CRYS_TRIGONAL: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(0); + if(editC) editC->setEnabled(0); + if(editAlpha) editAlpha->setEnabled(1); + if(editBeta) editBeta->setEnabled(0); + if(editGamma) editGamma->setEnabled(0); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(0); + if(editCRecip) editCRecip->setEnabled(0); + if(editAlphaRecip) editAlphaRecip->setEnabled(1); + if(editBetaRecip) editBetaRecip->setEnabled(0); + if(editGammaRecip) editGammaRecip->setEnabled(0); + + if(editB) editB->setText(editA->text()); + if(editC) editC->setText(editA->text()); + if(editBRecip) editBRecip->setText(editARecip->text()); + if(editCRecip) editCRecip->setText(editARecip->text()); + if(editBeta) editBeta->setText(editAlpha->text()); + if(editGamma) editGamma->setText(editAlpha->text()); + if(editBetaRecip) editBetaRecip->setText(editAlphaRecip->text()); + if(editGammaRecip) editGammaRecip->setText(editAlphaRecip->text()); + break; + + case CRYS_TRICLINIC: + case CRYS_NOT_SET: + default: + if(editA) editA->setEnabled(1); + if(editB) editB->setEnabled(1); + if(editC) editC->setEnabled(1); + if(editAlpha) editAlpha->setEnabled(1); + if(editBeta) editBeta->setEnabled(1); + if(editGamma) editGamma->setEnabled(1); + + if(editARecip) editARecip->setEnabled(1); + if(editBRecip) editBRecip->setEnabled(1); + if(editCRecip) editCRecip->setEnabled(1); + if(editAlphaRecip) editAlphaRecip->setEnabled(1); + if(editBetaRecip) editBetaRecip->setEnabled(1); + if(editGammaRecip) editGammaRecip->setEnabled(1); + break; + } +} +#endif diff --git a/libs/spacegroups/crystalsys.h b/libs/spacegroups/crystalsys.h new file mode 100644 index 0000000..a8cad46 --- /dev/null +++ b/libs/spacegroups/crystalsys.h @@ -0,0 +1,37 @@ +/* + * Crystal Systems + * @author Tobias Weber + * @date oct-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_CRYSSYS_H__ +#define __TAKIN_CRYSSYS_H__ + +enum CrystalSystem +{ + CRYS_NOT_SET, + + CRYS_TRICLINIC, // all params free + CRYS_MONOCLINIC, // beta=gamma=90 + CRYS_ORTHORHOMBIC, // alpha=beta=gamma=90 + CRYS_TETRAGONAL, // a=b, alpha=beta=gamma=90 + CRYS_TRIGONAL, // a=b=c, alpha=beta=gamma + CRYS_HEXAGONAL, // a=b, gamma=120, alpha=beta=90 + CRYS_CUBIC // a=b=c, alpha=beta=gamma=90 +}; + +extern CrystalSystem get_crystal_system_from_laue_group(const char* pcLaue); +extern const char* get_crystal_system_name(CrystalSystem ty); + +#ifndef NO_QT +#include + +extern void set_crystal_system_edits(CrystalSystem crystalsys, + QLineEdit* pA, QLineEdit* pB, QLineEdit* pC, + QLineEdit* pAlpha, QLineEdit* pBeta, QLineEdit* pGamma, + QLineEdit* pAReci=nullptr, QLineEdit* pBReci=nullptr, QLineEdit* pCReci=nullptr, + QLineEdit* pAlphaReci=nullptr, QLineEdit* pBetaReci=nullptr, QLineEdit* pGammaReci=nullptr); +#endif + +#endif diff --git a/libs/spacegroups/latticehelper.h b/libs/spacegroups/latticehelper.h new file mode 100644 index 0000000..8b5fa5a --- /dev/null +++ b/libs/spacegroups/latticehelper.h @@ -0,0 +1,204 @@ +/** + * Lattice Helpers + * @author Tobias Weber + * @date 2015-2016 + * @license GPLv2 + */ + +#ifndef __LATTICE_HELPER_H__ +#define __LATTICE_HELPER_H__ + +#include "tlibs/math/linalg.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/geo.h" + +#include "spacegroup.h" +#include "../formfactors/formfact.h" + +namespace ublas = tl::ublas; + + +template +struct AtomPos +{ + std::string strAtomName; + ublas::vector vecPos; + + t_real J; // optional: coupling +}; + + +template +struct LatticeCommon +{ + using t_mat = ublas::matrix; + using t_vec = ublas::vector; + + tl::Lattice lattice, recip; + tl::Plane planeRLU, planeFrac; + + const SpaceGroup* pSpaceGroup = nullptr; + const std::vector>* pvecAtomPos = nullptr; + + t_mat matPlane, matPlane_inv; + t_mat matPlaneReal, matPlaneReal_inv; + + std::vector vecAllNames; + std::vector vecAllAtoms, vecAllAtomsFrac; + std::vector vecAllAtomTypes; + std::vector> vecScatlens; + + t_vec dir0RLU, dir1RLU; + t_mat matA, matB; + + tl::Plane plane, planeReal; + + + LatticeCommon() = default; + ~LatticeCommon() = default; + + bool Calc(const tl::Lattice& lat, const tl::Lattice& rec, + const tl::Plane& plRLU, const tl::Plane& plFrac, + const SpaceGroup *pSG, const std::vector>* pvecAt) + { + lattice = lat; + recip = rec; + planeRLU = plRLU; + planeFrac = plFrac; + pSpaceGroup = pSG; + pvecAtomPos = pvecAt; + + { // reciprocal lattice + t_vec vecX0 = ublas::zero_vector(3); + t_vec vecPlaneX = planeRLU.GetDir0()[0] * recip.GetVec(0) + + planeRLU.GetDir0()[1] * recip.GetVec(1) + + planeRLU.GetDir0()[2] * recip.GetVec(2); + t_vec vecPlaneY = planeRLU.GetDir1()[0] * recip.GetVec(0) + + planeRLU.GetDir1()[1] * recip.GetVec(1) + + planeRLU.GetDir1()[2] * recip.GetVec(2); + plane = tl::Plane(vecX0, vecPlaneX, vecPlaneY); + + std::vector vecOrth = + tl::gram_schmidt( + {plane.GetDir0(), plane.GetDir1(), plane.GetNorm()}, 1); + matPlane = tl::column_matrix(vecOrth); + t_real dDir0Len = ublas::norm_2(vecOrth[0]), dDir1Len = ublas::norm_2(vecOrth[1]); + + if(tl::float_equal(dDir0Len, 0.) || tl::float_equal(dDir1Len, 0.) + || tl::is_nan_or_inf(dDir0Len) || tl::is_nan_or_inf(dDir1Len)) + { + tl::log_err("Invalid scattering plane."); + return false; + } + + bool bInv = tl::inverse(matPlane, matPlane_inv); + if(!bInv) + { + tl::log_err("Cannot invert scattering plane metric."); + return false; + } + } + + { // real lattice + t_vec vecX0 = ublas::zero_vector(3); + t_vec vecPlaneX = planeFrac.GetDir0()[0] * lattice.GetVec(0) + + planeFrac.GetDir0()[1] * lattice.GetVec(1) + + planeFrac.GetDir0()[2] * lattice.GetVec(2); + t_vec vecPlaneY = planeFrac.GetDir1()[0] * lattice.GetVec(0) + + planeFrac.GetDir1()[1] * lattice.GetVec(1) + + planeFrac.GetDir1()[2] * lattice.GetVec(2); + planeReal = tl::Plane(vecX0, vecPlaneX, vecPlaneY); + + std::vector vecOrth = + tl::gram_schmidt( + {planeReal.GetDir0(), planeReal.GetDir1(), planeReal.GetNorm()}, 1); + matPlaneReal = tl::column_matrix(vecOrth); + t_real dDir0Len = ublas::norm_2(vecOrth[0]), dDir1Len = ublas::norm_2(vecOrth[1]); + + if(tl::float_equal(dDir0Len, 0.) || tl::float_equal(dDir1Len, 0.) + || tl::is_nan_or_inf(dDir0Len) || tl::is_nan_or_inf(dDir1Len)) + { + tl::log_err("Invalid plane in real lattice."); + return false; + } + + bool bInv = tl::inverse(matPlaneReal, matPlaneReal_inv); + if(!bInv) + { + tl::log_err("Cannot invert plane metric in real lattice."); + return false; + } + } + + + matA = lattice.GetMetric(); + matB = recip.GetMetric(); + + dir0RLU = planeRLU.GetDir0(); + dir1RLU = planeRLU.GetDir1(); + + + // -------------------------------------------------------------------- + // structure factors + std::shared_ptr> lstsl + = ScatlenList::GetInstance(); + + const std::vector* pvecSymTrafos = nullptr; + if(pSpaceGroup) + pvecSymTrafos = &pSpaceGroup->GetTrafos(); + + if(pvecSymTrafos && pvecSymTrafos->size() && /*g_bHasFormfacts &&*/ + g_bHasScatlens && pvecAtomPos && pvecAtomPos->size()) + { + std::vector vecAtoms; + std::vector vecNames; + for(std::size_t iAtom=0; iAtomsize(); ++iAtom) + { + vecAtoms.push_back((*pvecAtomPos)[iAtom].vecPos); + vecNames.push_back((*pvecAtomPos)[iAtom].strAtomName); + } + + const t_real dUCSize = 1.; + std::tie(vecAllNames, vecAllAtoms, vecAllAtomsFrac, vecAllAtomTypes) = + tl::generate_all_atoms + (*pvecSymTrafos, vecAtoms, &vecNames, matA, + /*t_real(0), t_real(1)*/ -dUCSize/t_real(2), dUCSize/t_real(2), + g_dEps); + + for(std::size_t iAtom=0; iAtom::elem_type* pElem = lstsl->Find(strElem); + vecScatlens.push_back(pElem ? pElem->GetCoherent() : std::complex(0.,0.)); + if(!pElem) + tl::log_err("Element \"", strElem, "\" not found in scattering length table.", + " Using b=0."); + } + } + // -------------------------------------------------------------------- + + return true; + } + + + bool CanCalcStructFact() const { return vecScatlens.size() != 0; } + + std::tuple, t_real, t_real> GetStructFact(const t_vec& vecPeak) const + { + std::complex cF = + tl::structfact, t_vec, std::vector> + (vecAllAtoms, vecPeak, vecScatlens); + t_real dFsq = (std::conj(cF)*cF).real(); + t_real dF = std::sqrt(dFsq); + + return std::make_tuple(cF, dF, dFsq); + } +}; + + +#endif diff --git a/libs/spacegroups/sghelper.h b/libs/spacegroups/sghelper.h new file mode 100644 index 0000000..e7feb02 --- /dev/null +++ b/libs/spacegroups/sghelper.h @@ -0,0 +1,299 @@ +/* + * spacegroup helpers + * @author Tobias Weber + * @date oct-2015 + * @license GPLv2 + */ + +#ifndef __SG_HELPERS_H__ +#define __SG_HELPERS_H__ + +#include +#include +#include +#include +#include +#include "tlibs/math/linalg.h" +#include "tlibs/string/string.h" + +namespace ublas = tl::ublas; + + +template +std::string print_matrix(const ublas::matrix& mat) +{ + std::ostringstream ostr; + ostr.precision(4); + + for(int i=0; i +std::string print_vector(const ublas::vector& vec) +{ + std::ostringstream ostr; + ostr.precision(4); + + ostr << "("; + for(int i=0; i class t_cont = std::vector, + class t_mat = ublas::matrix> +bool is_mat_in_container(const t_cont& cont, const t_mat& mat) +{ + using t_real = typename t_mat::value_type; + t_real dEps = 1e-4; + + for(const t_mat& matCur : cont) + { + if(tl::mat_equal(matCur, mat, dEps)) + return true; + } + return false; +} + +template class t_cont = std::vector, + class t_vec = ublas::vector> +bool is_vec_in_container(const t_cont& cont, const t_vec& vec) +{ + using t_real = typename t_vec::value_type; + t_real dEps = 1e-4; + + for(const t_vec& vecCur : cont) + { + if(tl::vec_equal(vecCur, vec, dEps)) + return true; + } + return false; +} + +/*template> +bool is_inverting(const t_mat& mat) +{ + for(typename t_mat::size_type i=0; i<3; ++i) + for(typename t_mat::size_type j=0; j<3; ++j) + if(mat(i,j) > 0.) + return false; + + return true; +}*/ + +template +std::string get_trafo_desc(const ublas::matrix& mat) +{ + ublas::vector vecTrans = tl::make_vec({mat(0,3), mat(1,3), mat(2,3)}); + ublas::matrix matRot = mat; + matRot.resize(3,3, 1); + + ublas::vector vecX = tl::make_vec({1.,0.,0.}); + ublas::vector vecY = tl::make_vec({0.,1.,0.}); + ublas::vector vecZ = tl::make_vec({0.,0.,1.}); + + ublas::vector vecXR = ublas::prod(matRot, vecX); + ublas::vector vecYR = ublas::prod(matRot, vecY); + ublas::vector vecZR = ublas::prod(matRot, vecZ); + + std::ostringstream ostr; + ostr << "("; + for(int i=0; i<3; ++i) + { + bool bHasElem = 0; + if(!tl::float_equal(vecXR[i], 0.)) + { + double dVal = vecXR[i]; + + if(tl::float_equal(dVal, 1.)) + ostr << "x"; + else if(tl::float_equal(dVal, -1.)) + ostr << "-x"; + else + ostr << dVal << "x"; + bHasElem = 1; + } + if(!tl::float_equal(vecYR[i], 0.)) + { + double dVal = vecYR[i]; + + if(bHasElem) + { + if(dVal >= 0.) ostr << " + "; else ostr << " - "; + + if(tl::float_equal(std::fabs(dVal), 1.)) + ostr << "y"; + else + ostr << std::fabs(dVal) << "y"; + } + else + { + if(tl::float_equal(dVal, 1.)) + ostr << "y"; + else if(tl::float_equal(dVal, -1.)) + ostr << "-y"; + else + ostr << dVal << "y"; + } + bHasElem = 1; + } + if(!tl::float_equal(vecZR[i], 0.)) + { + double dVal = vecZR[i]; + + if(bHasElem) + { + if(dVal >= 0.) ostr << " + "; else ostr << " - "; + + if(tl::float_equal(std::fabs(dVal), 1.)) + ostr << "z"; + else + ostr << std::fabs(dVal) << "z"; + } + else + { + if(tl::float_equal(dVal, 1.)) + ostr << "z"; + else if(tl::float_equal(dVal, -1.)) + ostr << "-z"; + else + ostr << dVal << "z"; + } + bHasElem = 1; + } + + if(!tl::float_equal(vecTrans[i], 0.)) + { + double dVal = vecTrans[i]; + + if(bHasElem) + { + if(dVal >= 0.) ostr << " + "; else ostr << " - "; + ostr << std::fabs(dVal); + } + else + ostr << dVal; + } + + if(i<2) + ostr << ", "; + } + ostr << ")"; + return ostr.str(); +} + +// convert e.g.: "P 21 3" -> "P2_13" +template +void convert_hm_symbol(t_str& strHM) +{ + std::vector vecSyms; + tl::get_tokens(strHM, " ", vecSyms); + + for(t_str& str : vecSyms) + { + bool bLastWasDigit = 0; + for(std::size_t iC = 0; iC 23 +template +t_str get_pointgroup(const t_str& str) +{ + t_str strRet; + + // remove cell centering symbol + std::remove_copy_if(str.begin(), str.end(), + std::back_insert_iterator(strRet), + [](typename t_str::value_type c)->bool { return std::isupper(c); }); + + // remove screw axes + while(1) + { + std::size_t iPosScrew = strRet.find('_'); + if(iPosScrew == t_str::npos) + break; + strRet.erase(iPosScrew, 2); + } + + // mirror plane + std::replace_if(strRet.begin(), strRet.end(), + [](typename t_str::value_type c)->bool + { return c=='a'||c=='b'||c=='c'||c=='d'||c=='e'||c=='f'||c=='n'; }, + 'm' ); + return strRet; +} + + +/** + * check allowed Bragg reflections + * algorithm based on Clipper's HKL_class + * constructor in clipper/core/coords.cpp by K. Cowtan + */ +template class t_cont = std::vector, + class t_mat = ublas::matrix, + class t_vec = ublas::vector> +bool is_reflection_allowed(int h, int k, int l, const t_cont& vecTrafos) +{ + using t_real = typename t_mat::value_type; + const t_real dEps = t_real(1e-6); + t_vec vecHKL = tl::make_vec({t_real(h), t_real(k), t_real(l)}); + + for(const t_mat& mat : vecTrafos) + { + t_mat matRot = ublas::trans(mat); // recip -> transpose + matRot.resize(3,3,1); + t_vec vecHKL2 = ublas::prod(matRot, vecHKL); + + if(tl::vec_equal(vecHKL, vecHKL2, dEps)) + { + t_vec vecTrans = tl::make_vec({mat(0,3), mat(1,3), mat(2,3)}); + t_real dInner = ublas::inner_prod(vecTrans, vecHKL2); + t_real dMod = std::abs(std::fmod(dInner, t_real(1))); // map into [0,1] + + // not allowed if vecTrans and vecHKL2 not perpendicular + if(!tl::float_equal(dMod, t_real(0), dEps) && + !tl::float_equal(dMod, t_real(1), dEps)) + return false; + } + } + return true; +} + + +#endif diff --git a/libs/spacegroups/spacegroup.cpp b/libs/spacegroups/spacegroup.cpp new file mode 100644 index 0000000..21e898d --- /dev/null +++ b/libs/spacegroups/spacegroup.cpp @@ -0,0 +1,13 @@ +/* + * Loads tabulated spacegroups + * @author Tobias Weber + * @date feb-2016 + * @license GPLv2 + */ + +#include "spacegroup.h" +#include "spacegroup_impl.h" +#include "libs/globals.h" + +template class SpaceGroup; +template class SpaceGroups; diff --git a/libs/spacegroups/spacegroup.h b/libs/spacegroups/spacegroup.h new file mode 100644 index 0000000..18761df --- /dev/null +++ b/libs/spacegroups/spacegroup.h @@ -0,0 +1,137 @@ +/* + * Loads tabulated spacegroups + * @author Tobias Weber + * @date feb-2016 + * @license GPLv2 + */ + +#ifndef __SG_TAB_H__ +#define __SG_TAB_H__ + +#include "crystalsys.h" +#include "sghelper.h" +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#include "tlibs/file/prop.h" + +#include +#include + +namespace ublas = boost::numeric::ublas; + + +template +class SpaceGroup +{ +public: + using t_mat = ublas::matrix; + using t_vec = ublas::vector; + +protected: + unsigned int m_iNr = 0; + std::string m_strName; + std::string m_strLaue, m_strPoint; + CrystalSystem m_crystalsys; + std::string m_strCrystalSysName; + + std::vector m_vecTrafos; + std::vector m_vecInvTrafos, m_vecPrimTrafos, m_vecCenterTrafos; + +public: + SpaceGroup() = default; + ~SpaceGroup() = default; + SpaceGroup(const SpaceGroup& sg) + : m_iNr(sg.m_iNr), m_strName(sg.m_strName), m_strLaue(sg.m_strLaue), + m_strPoint(sg.m_strPoint), m_crystalsys(sg.m_crystalsys), + m_strCrystalSysName(sg.m_strCrystalSysName), m_vecTrafos(sg.m_vecTrafos), + m_vecInvTrafos(sg.m_vecInvTrafos), m_vecPrimTrafos(sg.m_vecPrimTrafos), + m_vecCenterTrafos(sg.m_vecCenterTrafos) + {} + SpaceGroup(SpaceGroup&& sg) + : m_iNr(sg.m_iNr), m_strName(std::move(sg.m_strName)), m_strLaue(std::move(sg.m_strLaue)), + m_strPoint(std::move(sg.m_strPoint)), m_crystalsys(std::move(sg.m_crystalsys)), + m_strCrystalSysName(std::move(sg.m_strCrystalSysName)), m_vecTrafos(std::move(sg.m_vecTrafos)), + m_vecInvTrafos(std::move(sg.m_vecInvTrafos)), m_vecPrimTrafos(std::move(sg.m_vecPrimTrafos)), + m_vecCenterTrafos(std::move(sg.m_vecCenterTrafos)) + {} + + bool HasReflection(int h, int k, int l) const + { + return is_reflection_allowed(h,k,l, m_vecTrafos); + } + + void SetNr(unsigned int iNr) { m_iNr = iNr; } + unsigned int GetNr() const { return m_iNr; } + + void SetName(const std::string& str) + { + m_strName = str; + m_strPoint = get_pointgroup(m_strName); + } + const std::string& GetName() const { return m_strName; } + + void SetCrystalSystem(const CrystalSystem& crys) + { + m_crystalsys = crys; + m_strCrystalSysName = get_crystal_system_name(m_crystalsys); + } + CrystalSystem GetCrystalSystem() const { return m_crystalsys; } + const std::string& GetCrystalSystemName() const { return m_strCrystalSysName; } + + void SetLaueGroup(const std::string& str) + { + m_strLaue = str; + SetCrystalSystem(get_crystal_system_from_laue_group(m_strLaue.c_str())); + } + const std::string& GetLaueGroup() const { return m_strLaue; } + const std::string& GetPointGroup() const { return m_strPoint; } + + void SetTrafos(std::vector&& vecTrafos) { m_vecTrafos = std::move(vecTrafos); } + void SetTrafos(const std::vector& vecTrafos) { m_vecTrafos = vecTrafos; } + const std::vector& GetTrafos() const { return m_vecTrafos; } + + void SetInvTrafos(std::vector&& vecTrafos) { m_vecInvTrafos = std::move(vecTrafos); } + void SetInvTrafos(const std::vector& vecTrafos) { m_vecInvTrafos = vecTrafos; } + void SetPrimTrafos(std::vector&& vecTrafos) { m_vecPrimTrafos = std::move(vecTrafos); } + void SetPrimTrafos(const std::vector& vecTrafos) { m_vecPrimTrafos = vecTrafos; } + void SetCenterTrafos(std::vector&& vecTrafos) { m_vecCenterTrafos = std::move(vecTrafos); } + void SetCenterTrafos(const std::vector& vecTrafos) { m_vecCenterTrafos = vecTrafos; } + + const std::vector& GetInvTrafos() const { return m_vecInvTrafos; } + const std::vector& GetPrimTrafos() const { return m_vecPrimTrafos; } + const std::vector& GetCenterTrafos() const { return m_vecCenterTrafos; } +}; + + +template +class SpaceGroups +{ + public: + typedef std::vector*> t_vecSpaceGroups; + typedef std::map> t_mapSpaceGroups; + + private: + static std::shared_ptr> s_inst; + static std::mutex s_mutex; + + SpaceGroups(); + + protected: + t_mapSpaceGroups g_mapSpaceGroups; + t_vecSpaceGroups g_vecSpaceGroups; + std::string s_strSrc, s_strUrl; + bool m_bOk = 0; + + public: + virtual ~SpaceGroups(); + static std::shared_ptr> GetInstance(); + + const t_mapSpaceGroups* get_space_groups() const; + const t_vecSpaceGroups* get_space_groups_vec() const; + const std::string& get_sgsource(bool bUrl=0) const; + + bool IsOk() const { return m_bOk; } +}; + + +#endif diff --git a/libs/spacegroups/spacegroup_clp.cpp b/libs/spacegroups/spacegroup_clp.cpp new file mode 100644 index 0000000..a7bce1a --- /dev/null +++ b/libs/spacegroups/spacegroup_clp.cpp @@ -0,0 +1,113 @@ +/* + * Wrapper for clipper spacegroups + * @author Tobias Weber + * @date oct-2015 + * @license GPLv2 + */ + +#include "spacegroup_clp.h" +#include +#include "tlibs/log/log.h" + + +SpaceGroupClp::SpaceGroupClp(unsigned int iNum) + : m_psg(new clipper::Spacegroup(clipper::Spgr_descr(iNum))) +{ + m_strName = m_psg->symbol_hm(); + convert_hm_symbol(m_strName); + + m_strLaue = m_psg->symbol_laue(); + m_crystalsys = get_crystal_system_from_laue_group(m_strLaue.c_str()); +} + +SpaceGroupClp::~SpaceGroupClp() +{ + if(m_psg) { delete m_psg; m_psg = nullptr; } +} + +SpaceGroupClp::SpaceGroupClp(const SpaceGroupClp& sg) + : m_psg(new clipper::Spacegroup(sg.m_psg->descr())), + m_strName(sg.GetName()), m_strLaue(sg.GetLaueGroup()), + m_crystalsys(sg.GetCrystalSystem()) +{} + +SpaceGroupClp::SpaceGroupClp(SpaceGroupClp&& sg) +{ + m_psg = sg.m_psg; + sg.m_psg = nullptr; + + m_strName = std::move(sg.m_strName); + m_strLaue = std::move(sg.m_strLaue); + m_crystalsys = std::move(sg.m_crystalsys); +} + +// direct calculation of allowed bragg peaks +bool SpaceGroupClp::HasReflection(int h, int k, int l) const +{ + if(!m_psg) return false; + + std::vector> vecTrafos; + GetSymTrafos(vecTrafos); + return is_reflection_allowed, ublas::vector>(h,k,l, vecTrafos); +} + +// using clipper +bool SpaceGroupClp::HasReflection2(int h, int k, int l) const +{ + if(!m_psg) return false; + + clipper::HKL_class hkl = m_psg->hkl_class(clipper::HKL(h,k,l)); + return !hkl.sys_abs(); +} + +void SpaceGroupClp::GetSymTrafos(std::vector>& vecTrafos) const +{ + get_symtrafos(*m_psg, vecTrafos, SymTrafoType::ALL); +} +void SpaceGroupClp::GetInvertingSymTrafos(std::vector>& vecTrafos) const +{ + get_symtrafos(*m_psg, vecTrafos, SymTrafoType::INVERTING); +} +void SpaceGroupClp::GetPrimitiveSymTrafos(std::vector>& vecTrafos) const +{ + get_symtrafos(*m_psg, vecTrafos, SymTrafoType::PRIMITIVE); +} +void SpaceGroupClp::GetCenteringSymTrafos(std::vector>& vecTrafos) const +{ + get_symtrafos(*m_psg, vecTrafos, SymTrafoType::CENTERING); +} + + +// ----------------------------------------------------------------------------- + + +static t_mapSpaceGroups g_mapSpaceGroups; + +void init_space_groups() +{ + if(!g_mapSpaceGroups.empty()) + { + tl::log_warn("Space Groups have already been initialised."); + return; + } + + typedef t_mapSpaceGroups::value_type t_val; + + for(int iSg=1; iSg<=230; ++iSg) + { + SpaceGroupClp sg(iSg); + g_mapSpaceGroups.insert(t_val(sg.GetName(), std::move(sg))); + } +} + +const t_mapSpaceGroups* get_space_groups() +{ + if(g_mapSpaceGroups.empty()) + { + tl::log_warn("Space Groups had not been initialised properly."); + init_space_groups(); + } + + return &g_mapSpaceGroups; +} diff --git a/libs/spacegroups/spacegroup_clp.h b/libs/spacegroups/spacegroup_clp.h new file mode 100644 index 0000000..16ebe00 --- /dev/null +++ b/libs/spacegroups/spacegroup_clp.h @@ -0,0 +1,125 @@ +/* + * Wrapper for clipper spacegroups + * @author Tobias Weber + * @date oct-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_SGCLP_H__ +#define __TAKIN_SGCLP_H__ + +#include +#include +#include "crystalsys.h" +#include "tlibs/string/string.h" +#include "sghelper.h" + +namespace ublas = boost::numeric::ublas; + + +class SpaceGroupClp +{ +protected: + clipper::Spacegroup *m_psg = nullptr; + std::string m_strName; + std::string m_strLaue; + CrystalSystem m_crystalsys; + +public: + SpaceGroupClp(unsigned int iNum); + SpaceGroupClp(const SpaceGroupClp& sg); + SpaceGroupClp(SpaceGroupClp&& sg); + SpaceGroupClp() = delete; + ~SpaceGroupClp(); + + bool HasReflection(int h, int k, int l) const; + bool HasReflection2(int h, int k, int l) const; + + void SetName(const std::string& str) { m_strName = str; } + const std::string& GetName() const { return m_strName; } + + const std::string& GetLaueGroup() const { return m_strLaue; } + + CrystalSystem GetCrystalSystem() const { return m_crystalsys; } + const char* GetCrystalSystemName() const { return get_crystal_system_name(m_crystalsys); } + + void GetSymTrafos(std::vector>& vecTrafos) const; + void GetInvertingSymTrafos(std::vector>& vecTrafos) const; + void GetPrimitiveSymTrafos(std::vector>& vecTrafos) const; + void GetCenteringSymTrafos(std::vector>& vecTrafos) const; +}; + + +typedef std::map t_mapSpaceGroups; +extern const t_mapSpaceGroups* get_space_groups(); +extern void init_space_groups(); + + +template +ublas::matrix symop_to_matrix(const clipper::Symop& symop) +{ + const clipper::Mat33& mat = symop.rot(); + const clipper::Vec3& vec = symop.trn(); + + ublas::matrix matRet(4,4); + for(int i=0; i<3; ++i) + for(int j=0; j<3; ++j) + matRet(i,j) = T(mat(i,j)); + + for(int i=0; i<3; ++i) + { + matRet(i,3) = T(vec[i]); + matRet(3,i) = 0.; + } + + matRet(3,3) = 1.; + return matRet; +} + + +enum class SymTrafoType +{ + ALL, + + PRIMITIVE, + INVERTING, + CENTERING +}; + +template +void get_symtrafos(const clipper::Spacegroup& sg, + std::vector>& vecTrafos, SymTrafoType ty=SymTrafoType::ALL) +{ + int iNumSymOps = 0; + + if(ty == SymTrafoType::ALL) + iNumSymOps = sg.num_symops(); + else if(ty == SymTrafoType::INVERTING) + iNumSymOps = sg.num_inversion_symops(); + else if(ty == SymTrafoType::PRIMITIVE) + iNumSymOps = sg.num_primitive_symops(); + else if(ty == SymTrafoType::CENTERING) + iNumSymOps = sg.num_centering_symops(); + + vecTrafos.clear(); + vecTrafos.reserve(iNumSymOps); + + for(int iSymOp=0; iSymOp mat = symop_to_matrix(*symop); + vecTrafos.push_back(mat); + } +} + +#endif diff --git a/libs/spacegroups/spacegroup_impl.h b/libs/spacegroups/spacegroup_impl.h new file mode 100644 index 0000000..582aacd --- /dev/null +++ b/libs/spacegroups/spacegroup_impl.h @@ -0,0 +1,142 @@ +/** + * Loads tabulated spacegroups + * @author Tobias Weber + * @date feb-2016 + * @license GPLv2 + */ + +#ifndef __SG_TAB_IMPL_H__ +#define __SG_TAB_IMPL_H__ + +#include +#include "libs/globals.h" // find_resource + +template +SpaceGroups::SpaceGroups() +{ + tl::log_debug("Loading space groups."); + + using t_mat = typename SpaceGroup::t_mat; + //using t_vec = typename SpaceGroup::t_vec; + + tl::Prop xml; + if(!xml.Load(find_resource("res/sgroups.xml").c_str(), tl::PropType::XML)) + return; + + unsigned int iNumSGs = xml.Query("sgroups/num_groups", 0); + if(iNumSGs < 230) + tl::log_warn("Less than 230 space groups are defined!"); + + + g_vecSpaceGroups.reserve(iNumSGs); + typedef typename t_mapSpaceGroups::value_type t_val; + + for(unsigned int iSg=0; iSg((strGroup+"/number").c_str()); + std::string strName = tl::trimmed(xml.Query((strGroup+"/name").c_str())); + std::string strLaue = tl::trimmed(xml.Query((strGroup+"/lauegroup").c_str())); + unsigned int iNumTrafos = xml.Query((strGroup+"/num_trafos").c_str()); + + std::vector vecTrafos; + std::vector vecInvTrafos, vecPrimTrafos, vecCenterTrafos; + vecTrafos.reserve(iNumTrafos); + + for(unsigned int iTrafo=0; iTrafo(strTrafo.c_str()); + std::pair pairSg = tl::split_first(strTrafoVal, std::string(";"), 1); + + std::istringstream istrMat(pairSg.first); + t_mat mat; + istrMat >> mat; + + for(typename std::string::value_type c : pairSg.second) + { + if(std::tolower(c)=='p') vecPrimTrafos.push_back(iTrafo); + if(std::tolower(c)=='i') vecInvTrafos.push_back(iTrafo); + if(std::tolower(c)=='c') vecCenterTrafos.push_back(iTrafo); + } + + vecTrafos.push_back(std::move(mat)); + } + + SpaceGroup sg; + sg.SetNr(iSgNr); + sg.SetName(strName); + sg.SetLaueGroup(strLaue); + sg.SetTrafos(std::move(vecTrafos)); + sg.SetInvTrafos(std::move(vecInvTrafos)); + sg.SetPrimTrafos(std::move(vecPrimTrafos)); + sg.SetCenterTrafos(std::move(vecCenterTrafos)); + + g_mapSpaceGroups.insert(t_val(sg.GetName(), std::move(sg))); + } + + g_vecSpaceGroups.reserve(g_mapSpaceGroups.size()); + for(const t_val& pairSg : g_mapSpaceGroups) + g_vecSpaceGroups.push_back(&pairSg.second); + + std::sort(g_vecSpaceGroups.begin(), g_vecSpaceGroups.end(), + [](const SpaceGroup* sg1, const SpaceGroup* sg2) -> bool + { return sg1->GetNr() <= sg2->GetNr(); }); + + + s_strSrc = xml.Query("sgroups/source", ""); + s_strUrl = xml.Query("sgroups/source_url", ""); + m_bOk = 1; +} + +template +SpaceGroups::~SpaceGroups() {} + +template +std::shared_ptr> SpaceGroups::GetInstance() +{ + std::lock_guard _guard(s_mutex); + + if(!s_inst) + s_inst = std::shared_ptr(new SpaceGroups()); + + return s_inst; +} + +template +const typename SpaceGroups::t_mapSpaceGroups* SpaceGroups::get_space_groups() const +{ + if(g_mapSpaceGroups.empty()) + tl::log_warn("Space Groups had not been initialised properly."); + + return &g_mapSpaceGroups; +} + +template +const typename SpaceGroups::t_vecSpaceGroups* SpaceGroups::get_space_groups_vec() const +{ + if(g_vecSpaceGroups.empty()) + tl::log_warn("Space Groups had not been initialised properly."); + + return &g_vecSpaceGroups; +} + +template +const std::string& SpaceGroups::get_sgsource(bool bUrl) const +{ + return bUrl ? s_strUrl : s_strSrc ; +} + + +// statics +template std::shared_ptr> SpaceGroups::s_inst = nullptr; +template std::mutex SpaceGroups::s_mutex; + + +#endif diff --git a/libs/version.h b/libs/version.h new file mode 100644 index 0000000..dd42777 --- /dev/null +++ b/libs/version.h @@ -0,0 +1,13 @@ +/** + * takin + * @author tweber + * @date 2014-2016 + * @license GPLv2 + */ + +#ifndef __TAZ_VERSION_H__ +#define __TAZ_VERSION_H__ + +#define TAKIN_VER "1.0.1" + +#endif diff --git a/monteconvo b/monteconvo new file mode 120000 index 0000000..6aaa855 --- /dev/null +++ b/monteconvo @@ -0,0 +1 @@ +bin/monteconvo \ No newline at end of file diff --git a/monteconvo.project b/monteconvo.project new file mode 100644 index 0000000..fdd48dd --- /dev/null +++ b/monteconvo.project @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + diff --git a/montereso b/montereso new file mode 120000 index 0000000..fbdc573 --- /dev/null +++ b/montereso @@ -0,0 +1 @@ +bin/montereso \ No newline at end of file diff --git a/montereso.project b/montereso.project new file mode 100644 index 0000000..df7d83d --- /dev/null +++ b/montereso.project @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + diff --git a/obj/.dir b/obj/.dir new file mode 100644 index 0000000..f2453eb --- /dev/null +++ b/obj/.dir @@ -0,0 +1 @@ +temporary directory for object files diff --git a/plugins/.dir b/plugins/.dir new file mode 100644 index 0000000..23799c5 --- /dev/null +++ b/plugins/.dir @@ -0,0 +1 @@ +directory for plugins diff --git a/posextract b/posextract new file mode 120000 index 0000000..96a9e59 --- /dev/null +++ b/posextract @@ -0,0 +1 @@ +bin/posextract \ No newline at end of file diff --git a/prebuild.sh b/prebuild.sh new file mode 100755 index 0000000..ed4286c --- /dev/null +++ b/prebuild.sh @@ -0,0 +1,119 @@ +#!/bin/bash + + +if [[ $# -ge 3 ]]; then + UIC="$1" + MOC="$2" + + TAKINROOT="$3" + FORCE=0 +else + UIC="$(which uic-qt4)" + MOC="$(which moc-qt4)" + +# UIC="$(which uic-qt5)" +# MOC="$(which moc-qt5)" + + if [ $? -ne 0 ]; then + UIC="$(which uic)" + MOC="$(which moc)" + fi + + TAKINROOT=. + FORCE=1 # force rebuild when manually called +fi + + +if [ -z "$UIC" ] || [ -z "${MOC}" ]; then + echo "Error: moc/uic tools not found!"; + exit -1; +fi + +echo -e "Using UIC: ${UIC}\nUsing MOC: ${MOC}\n" + + + +echo -e "--------------------------------------------------------------------------------" +echo -e "building uis..." + +cd "${TAKINROOT}/ui" +for file in *.ui; do + outfile=ui_${file%\.ui}.h + + if [ ! -e ${outfile} -o "${FORCE}" -eq "1" ]; then + echo -e "${file} -> ${outfile}" + ${UIC} ${file} -o ${outfile} + fi +done +cd .. + + +echo -e "--------------------------------------------------------------------------------" +echo -e "\n" + + + + +echo -e "--------------------------------------------------------------------------------" +echo -e "building mocs..." + +declare -a hfiles=( + "${TAKINROOT}/tools/taz/taz.h" + "${TAKINROOT}/tools/taz/scattering_triangle.h" + "${TAKINROOT}/tools/taz/real_lattice.h" + "${TAKINROOT}/tools/taz/proj_lattice.h" + "${TAKINROOT}/tools/taz/tas_layout.h" + "${TAKINROOT}/tools/taz/tof_layout.h" + "${TAKINROOT}/tools/taz/recip3d.h" + "${TAKINROOT}/tools/taz/net.h" + "${TAKINROOT}/tools/taz/nicos.h" + "${TAKINROOT}/tools/taz/sics.h" + "${TAKINROOT}/tools/res/ResoDlg.h" + "${TAKINROOT}/tools/scanviewer/scanviewer.h" + "${TAKINROOT}/tools/monteconvo/ConvoDlg.h" + "${TAKINROOT}/tools/monteconvo/SqwParamDlg.h" + "${TAKINROOT}/tools/sglist/SgListDlg.h" + "${TAKINROOT}/dialogs/EllipseDlg.h" + "${TAKINROOT}/dialogs/EllipseDlg3D.h" + "${TAKINROOT}/dialogs/RecipParamDlg.h" + "${TAKINROOT}/dialogs/RealParamDlg.h" + "${TAKINROOT}/dialogs/SpurionDlg.h" + "${TAKINROOT}/dialogs/NeutronDlg.h" + "${TAKINROOT}/dialogs/SrvDlg.h" + "${TAKINROOT}/dialogs/GotoDlg.h" + "${TAKINROOT}/dialogs/AtomsDlg.h" + "${TAKINROOT}/dialogs/NetCacheDlg.h" + "${TAKINROOT}/dialogs/PowderDlg.h" + "${TAKINROOT}/dialogs/SettingsDlg.h" + "${TAKINROOT}/dialogs/DWDlg.h" + "${TAKINROOT}/dialogs/DynPlaneDlg.h" + "${TAKINROOT}/dialogs/FilePreviewDlg.h" + "${TAKINROOT}/dialogs/FormfactorDlg.h" + "${TAKINROOT}/dialogs/AboutDlg.h" + "${TAKINROOT}/dialogs/DispDlg.h" +) + +for hfile in ${hfiles[@]}; do + mocfile=${hfile%\.h}.moc + + if [ ! -e ${mocfile} -o "${FORCE}" -eq "1" ]; then + echo -e "${hfile} -> ${mocfile}" + ${MOC} ${hfile} -o ${mocfile} + fi +done + +echo -e "--------------------------------------------------------------------------------" +echo -e "\n" + + +echo -e "--------------------------------------------------------------------------------" +echo -e "building docs..." + +qcollectiongenerator ${TAKINROOT}/doc/takin.qhcp -o ${TAKINROOT}/doc/takin.qhc +cp -v ${TAKINROOT}/doc/takin.qhc ${TAKINROOT}/res/ +cp -v ${TAKINROOT}/doc/takin.qch ${TAKINROOT}/res/ + +echo -e "--------------------------------------------------------------------------------" + + +exit 0 diff --git a/reso b/reso new file mode 120000 index 0000000..9492fc7 --- /dev/null +++ b/reso @@ -0,0 +1 @@ +bin/reso \ No newline at end of file diff --git a/scanviewer b/scanviewer new file mode 120000 index 0000000..69d334d --- /dev/null +++ b/scanviewer @@ -0,0 +1 @@ +bin/scanviewer \ No newline at end of file diff --git a/scanviewer.project b/scanviewer.project new file mode 100644 index 0000000..d9ee738 --- /dev/null +++ b/scanviewer.project @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + diff --git a/setup_externals.sh b/setup_externals.sh new file mode 100755 index 0000000..e8cbfaf --- /dev/null +++ b/setup_externals.sh @@ -0,0 +1,156 @@ +#!/bin/bash + +GTAR="$(which gnutar)" +if [ $? -ne 0 ]; then + GTAR="$(which tar)" +fi + +FINDQWT=http://cmake.org/Wiki/images/2/27/FindQwt.cmake +TANGOICONS=http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz +SCATLENS=https://www.ncnr.nist.gov/resources/n-lengths/list.html +MAGFFACT_J0_1=https://www.ill.eu/sites/ccsl/ffacts/ffactnode5.html +MAGFFACT_J0_2=https://www.ill.eu/sites/ccsl/ffacts/ffactnode6.html +MAGFFACT_J0_3=https://www.ill.eu/sites/ccsl/ffacts/ffactnode7.html +MAGFFACT_J0_4=https://www.ill.eu/sites/ccsl/ffacts/ffactnode8.html +MAGFFACT_J2_1=https://www.ill.eu/sites/ccsl/ffacts/ffactnode9.html +MAGFFACT_J2_2=https://www.ill.eu/sites/ccsl/ffacts/ffactnode10.html +MAGFFACT_J2_3=https://www.ill.eu/sites/ccsl/ffacts/ffactnode11.html +MAGFFACT_J2_4=https://www.ill.eu/sites/ccsl/ffacts/ffactnode12.html + + +function dl_findqwt +{ +# rm -f FindQwt.cmake + + if [ ! -f FindQwt.cmake ]; then + echo -e "Downloading FindQwt...\n" + + if ! wget ${FINDQWT}; then + echo -e "Error: Cannot download FindQwt."; + exit -1; + fi + fi +} + + +function dl_tangoicons +{ +# rm -f tmp/tango-icon-theme.tar.gz + + if [ ! -f tmp/tango-icon-theme.tar.gz ]; then + echo -e "Downloading Tango icons...\n" + + if ! wget ${TANGOICONS} -O tmp/tango-icon-theme.tar.gz; then + echo -e "Error: Cannot download Tango icons."; + exit -1; + fi + fi + + + echo -e "Extracting Tango icons...\n" + cd tmp + + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/document-save.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/document-save-as.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/document-open.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/document-new.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/list-add.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/list-remove.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/system-log-out.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/view-refresh.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/media-playback-start.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/actions/media-playback-stop.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/categories/preferences-system.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/devices/media-floppy.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/devices/drive-harddisk.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/devices/network-wireless.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/mimetypes/image-x-generic.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/mimetypes/x-office-spreadsheet-template.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/apps/accessories-calculator.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/status/network-transmit-receive.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/status/network-offline.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/status/dialog-information.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/status/weather-snow.svg --strip-components=3 + ${GTAR} --wildcards -xzvf tango-icon-theme.tar.gz */scalable/apps/help-browser.svg --strip-components=3 + + cd .. + mv -v tmp/*.svg res/ +} + +function dl_scatlens +{ + if [ ! -f tmp/scatlens.html ]; then + echo -e "Downloading scattering length list...\n" + +# if ! wget ${SCATLENS} -O tmp/${SCATLENS##*/}; then +# echo -e "Error: Cannot download scattering length list."; +# exit -1; +# fi + + if [ ! -f tmp/${SCATLENS##*/} ]; then + echo -e "Files cannot be automatically downloaded. " + echo -e "Please download the following file manually and place them in the ./tmp subfolder:\n" + echo -e "\t${SCATLENS}\n" + echo -e "Afterwards, please run this script again.\n" + else + cp -v tmp/${SCATLENS##*/} tmp/scatlens.html + fi + fi +} + +function dl_magffacts +{ + if [ ! -f tmp/j2_4.html ]; then + echo -e "Obtaining magnetic form factor lists...\n" + +# if ! (wget ${MAGFFACT_J0_1} -O tmp/${MAGFFACT_J0_1##*/} && +# wget ${MAGFFACT_J0_2} -O tmp/${MAGFFACT_J0_2##*/} && +# wget ${MAGFFACT_J0_3} -O tmp/${MAGFFACT_J0_3##*/} && +# wget ${MAGFFACT_J0_4} -O tmp/${MAGFFACT_J0_4##*/} && +# +# wget ${MAGFFACT_J2_1} -O tmp/${MAGFFACT_J2_1##*/} && +# wget ${MAGFFACT_J2_2} -O tmp/${MAGFFACT_J2_2##*/} && +# wget ${MAGFFACT_J2_3} -O tmp/${MAGFFACT_J2_3##*/} && +# wget ${MAGFFACT_J2_4} -O tmp/${MAGFFACT_J2_4##*/}); then +# echo -e "Error: Cannot download magnetic form factor lists."; +# exit -1; +# fi + + if [ ! -f tmp/${MAGFFACT_J2_4##*/} ]; then + echo -e "Files cannot be automatically downloaded. " + echo -e "Please download the following files manually and place them in the ./tmp subfolder:\n" + echo -e "\t${MAGFFACT_J0_1}" + echo -e "\t${MAGFFACT_J0_2}" + echo -e "\t${MAGFFACT_J0_3}" + echo -e "\t${MAGFFACT_J0_4}" + echo -e "\t${MAGFFACT_J2_1}" + echo -e "\t${MAGFFACT_J2_2}" + echo -e "\t${MAGFFACT_J2_3}" + echo -e "\t${MAGFFACT_J2_4}\n" + echo -e "Afterwards, please run this script again.\n" + else + cp -v tmp/${MAGFFACT_J0_1##*/} tmp/j0_1.html + cp -v tmp/${MAGFFACT_J0_2##*/} tmp/j0_2.html + cp -v tmp/${MAGFFACT_J0_3##*/} tmp/j0_3.html + cp -v tmp/${MAGFFACT_J0_4##*/} tmp/j0_4.html + cp -v tmp/${MAGFFACT_J2_1##*/} tmp/j2_1.html + cp -v tmp/${MAGFFACT_J2_2##*/} tmp/j2_2.html + cp -v tmp/${MAGFFACT_J2_3##*/} tmp/j2_3.html + cp -v tmp/${MAGFFACT_J2_4##*/} tmp/j2_4.html + fi + fi +} + + +mkdir tmp +echo -e "--------------------------------------------------------------------------------" +dl_scatlens +echo -e "--------------------------------------------------------------------------------" +dl_magffacts +echo -e "--------------------------------------------------------------------------------" +dl_tangoicons +echo -e "--------------------------------------------------------------------------------" +dl_findqwt +echo -e "--------------------------------------------------------------------------------" + +echo -e "\nAfter successfully obtaining all resource files, the program ./gentab has to be run!\n" diff --git a/setup_makelists.sh b/setup_makelists.sh new file mode 100755 index 0000000..27321cc --- /dev/null +++ b/setup_makelists.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +DLG=$(which dialog 2>/dev/null) +if [ "$DLG" == "" ]; then DLG="/usr/bin/dialog"; fi + + +if [ ! -x $DLG ] +then + echo -e "Could not find dialog tool." + exit -1 +else + dlg_selected=$(${DLG} --stdout --title "Makelists" \ + --menu "Setup Makelists" 12 50 4 \ + 1 "Native, with dynamic tlibs" \ + 2 "Native, with static tlibs" \ + 3 "Mingw cross compile, with static tlibs" \ + 4 "Minimal cli client, with static tlibs" \ + 2>&1) + if [ ! $? -eq 0 ] + then + echo -e "Aborting." + exit 1 + fi + + case $dlg_selected in + 1 ) + rm -f CMakeLists.txt + ln -sf CMakeLists-dynamic.txt CMakeLists.txt + ;; + 2 ) + rm -f CMakeLists.txt + ln -sf CMakeLists-static.txt CMakeLists.txt + ;; + 3 ) + rm -f CMakeLists.txt + ln -sf CMakeLists-static-mingw.txt CMakeLists.txt + ;; + 4 ) + rm -f CMakeLists.txt + ln -sf CMakeLists-static-cli.txt CMakeLists.txt + ;; + esac + +fi diff --git a/setup_paths.sh b/setup_paths.sh new file mode 100755 index 0000000..b54653b --- /dev/null +++ b/setup_paths.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# call with ". ./setup_paths.sh" + +export PATH=/opt/local/libexec/qt4/bin:/opt/local/bin:$PATH diff --git a/setup_tlibs.sh b/setup_tlibs.sh new file mode 100755 index 0000000..09f7d9f --- /dev/null +++ b/setup_tlibs.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +if [ $# -ge 1 -a "$1" == "latest" ]; then + TLIBS=tlibs-master +else + #TLIBS=tlibs-0.5.8 + TLIBS=tlibs-master # override for non-tagged version +fi + + +REPO=http://forge.frm2.tum.de/cgit/cgit.cgi/frm2/mira/tlibs.git/snapshot + +TLIBS_DIR=tlibs +THEARCH=.tar.bz2 + +function dl_tlibs +{ + echo -e "Downloading tlibs..." + rm -f ${TLIBS}${THEARCH} + + if ! wget ${REPO}/${TLIBS}${THEARCH} + then + echo -e "Error: Cannot download tlibs."; + exit -1; + fi + + if ! tar -xjvf ${TLIBS}${THEARCH} + then + echo -e "Error: Cannot extract tlibs."; + exit -1; + fi + + mv ${TLIBS} ${TLIBS_DIR} + rm -f ${TLIBS}${THEARCH} +} + + +if [ -L ${TLIBS_DIR} ] +then + echo -e "Error: Symbolic link \"${TLIBS_DIR}\" already exists. Aborting."; + exit -1; +fi + + +rm -rf ${TLIBS_DIR} +dl_tlibs diff --git a/setup_tlibs_fancy.sh b/setup_tlibs_fancy.sh new file mode 100755 index 0000000..c00d09e --- /dev/null +++ b/setup_tlibs_fancy.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +TLIBS=tlibs-master.tar.bz2 +REPO=http://forge.frm2.tum.de/cgit/cgit.cgi/frm2/mira/tlibs.git/snapshot +TLIBS_DIR=tlibs +DLG=$(which dialog 2>/dev/null) + +if [ "$DLG" == "" ]; then DLG="/usr/bin/dialog"; fi + +function dl_tlibs +{ + echo -e "Downloading tlibs..." + rm -f ${TLIBS} + + if ! wget ${REPO}/${TLIBS} + then + echo -e "Error: Cannot download tlibs."; + exit -1; + fi + + if ! tar -xjvf ${TLIBS} + then + echo -e "Error: Cannot extract tlibs."; + exit -1; + fi + + mv tlibs-master ${TLIBS_DIR} + rm -f ${TLIBS} +} + +function link_tlibs +{ + echo -e "Linking tlibs..." + ln -sf ../tlibs +} + + +if [ -L ${TLIBS_DIR} ] +then + echo -e "Error: Symbolic link \"${TLIBS_DIR}\" already exists. Aborting."; + exit -1; +fi + + +rm -rf ${TLIBS_DIR} + + +if [ ! -x $DLG ] +then + dl_tlibs +else + dlg_selected=$(${DLG} --stdout --title "tlibs" \ + --menu "Setup tlibs" 10 40 2 \ + 1 "Download tlibs" \ + 2 "Link to ../tlibs" \ + 2>&1) + if [ ! $? -eq 0 ] + then + echo -e "Aborting." + exit 1 + fi + + case $dlg_selected in + 1 ) + dl_tlibs;; + 2 ) + link_tlibs;; + esac + +fi diff --git a/sfact b/sfact new file mode 120000 index 0000000..ae13a8d --- /dev/null +++ b/sfact @@ -0,0 +1 @@ +bin/sfact \ No newline at end of file diff --git a/sglist b/sglist new file mode 120000 index 0000000..0c98343 --- /dev/null +++ b/sglist @@ -0,0 +1 @@ +bin/sglist \ No newline at end of file diff --git a/takin b/takin new file mode 120000 index 0000000..5fc405f --- /dev/null +++ b/takin @@ -0,0 +1 @@ +bin/takin \ No newline at end of file diff --git a/takin.project b/takin.project new file mode 100644 index 0000000..0452b0f --- /dev/null +++ b/takin.project @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # ./prebuild.sh + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ./prebuild.sh + + + + + + + + + + None + + + + + + + + + + + + + + + diff --git a/takin.sh b/takin.sh new file mode 100755 index 0000000..0c8cb74 --- /dev/null +++ b/takin.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +TAKINDIR=$(dirname $0) +echo -e "Takin directory: ${TAKINDIR}" +LD_LIBRARY_PATH=./lib:${TAKINDIR}/lib:$LD_LIBRARY_PATH ${TAKINDIR}/bin/takin diff --git a/takin.workspace b/takin.workspace new file mode 100644 index 0000000..366b06d --- /dev/null +++ b/takin.workspace @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themakefile b/themakefile new file mode 100644 index 0000000..b6e56be --- /dev/null +++ b/themakefile @@ -0,0 +1,546 @@ +#CC = gcc +CC = clang + +DO_DEBUG = 0 +NATIVE_OPTS = 1 +IS_UNSTABLE = 0 +QT_VER = 4 +QWT_VER = 6 +USE_LAPACK = 0 +USE_3D = 1 +USE_NET = 1 +USE_IOSTR = 1 +USE_BOOST_REGEX = 0 +USE_GIL = 1 +USE_PY = 1 +USE_PLUGINS = 1 +USE_CPP11_ABI = 1 + +BOOST_SUFFIX = +#BOOST_SUFFIX = -mt +QWT5_SUFFIX = +#QWT5_SUFFIX = -qt4 + +# ----------------------------------------------------------------------------- + + +DEFINES = -DNO_JPEG -DNO_TIFF + +ifeq ($(IS_UNSTABLE), 1) + DEFINES += -DIS_EXPERIMENTAL_BUILD +endif + +ifeq ($(USE_3D), 1) + DEFINES += -DUSE_3D +else + DEFINES += -DNO_3D +endif + +ifeq ($(USE_NET), 1) + DEFINES += -DUSE_NET +else + DEFINES += -DNO_NET +endif + +ifeq ($(USE_IOSTR), 1) + DEFINES += -DUSE_IOSTR +else + DEFINES += -DNO_IOSTR +endif + +ifeq ($(USE_BOOST_REGEX), 1) + DEFINES += -DUSE_BOOST_REX +endif + +ifeq ($(USE_PY), 1) + DEFINES += -DUSE_PY +else + DEFINES += -DNO_PY +endif + +ifeq ($(USE_GIL), 1) + DEFINES += -DUSE_GIL +else + DEFINES += -DNO_GIL +endif + +ifeq ($(USE_PLUGINS), 1) + DEFINES += -DUSE_PLUGINS +else + DEFINES += -DNO_PLUGINS +endif + +DEFINES += -DQWT_VER=$(QWT_VER) +DEFINES += -DQT_VER=$(QT_VER) + + +# ----------------------------------------------------------------------------- + + +ifeq ($(QT_VER), 5) + QT_INC = -I/opt/local/libexec/qt5/include -I/opt/local/libexec/qt5/include/QtCore -I/opt/local/libexec/qt5/include/QtGui -I/opt/local/libexec/qt5/include/QtOpenGL \ + -I/usr/include/qt5 -I/usr/include/qt5/QtCore -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui \ + -I/usr/include/QtOpenGL + QT_LIB = -L/opt/local/libexec/qt5/lib -L/usr/lib64/qt5 -L/usr/lib/qt5/lib \ + -lQt5Widgets -lQt5Gui -lQt5Core -lQt5Svg -lQt5Concurrent + ifeq ($(USE_3D), 1) + QT_LIB += -lQt5OpenGL + endif +else + QT_INC = -I/opt/local/libexec/qt4/include -I/opt/local/libexec/qt4/include/QtCore -I/opt/local/libexec/qt4/include/QtGui -I/opt/local/libexec/qt4/include/QtOpenGL \ + -I/usr/include/qt4 -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL \ + -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtOpenGL + QT_LIB = -L/opt/local/libexec/qt4/lib -L/usr/lib64/qt4 -L/usr/lib/qt4/lib \ + -lQtCore -lQtGui -lQtSvg + ifeq ($(USE_3D), 1) + QT_LIB += -lQtOpenGL + endif +endif + +ifeq ($(QWT_VER), 6) + ifeq ($(QT_VER), 5) + QWT_INC = -I/opt/local/libexec/qt5/include/qwt \ + -I/usr/include/qt5/qwt -I/usr/include/qwt-qt5 + QWT_LIB = -lqwt-qt5 + else + QWT_INC = -I/opt/local/libexec/qt4/include/qwt \ + -I/usr/include/qwt6 -I/usr/include/qwt -I/usr/include/qwt-qt4 -I/usr/local/qwt/include + QWT_LIB = -L/usr/local/qwt/lib -lqwt + endif +else + QWT_INC = -I/usr/include/qwt5 -I/usr/include/qwt-qt4 -I/usr/local/qwt/include + QWT_LIB = -L/usr/local/qwt/lib -lqwt${QWT5_SUFFIX} +endif + + + +INC = ${QT_INC} ${QWT_INC} -I . -I/opt/local/include -I/usr/local/include \ + -I/opt/include -I/usr/include/freetype2 -I/usr/include/lapacke \ + -I/usr/include/python2.7 -I/usr/include/root -I/usr/include +LIB_DIRS = -L/opt/local/lib -L/opt/lib -L/usr/local/lib -L/usr/local/lib64 \ + -L/usr/lib64 -L/usr/lib64/root -L/usr/lib/x86_64-linux-gnu + + +STD_LIBS = -lstdc++ -lm +STD_LIBS += -lpthread + + +ifeq ($(DO_DEBUG), 0) + FLAGS = ${INC} -O2 -std=c++11 -DNDEBUG -Wall -Wpedantic -Wextra -fPIC + ifeq ($(NATIVE_OPTS), 1) + FLAGS += -march=native + else + FLAGS += -mtune=native + endif + FLAGS += -ffast-math + #FLAGS += -flto -fexpensive-optimizations + FLAGS += -DQT_NO_DEBUG + FLAGS += ${DEFINES} + STRIP = strip -v +else + FLAGS = ${INC} -std=c++11 -rdynamic -ggdb -DDEBUG -Wall -Wall -Wpedantic -Wextra -Weffc++ -fPIC ${DEFINES} + STRIP = echo Retaining debug symbols of +endif + + +FLAGS += -D_GLIBCXX_USE_CXX11_ABI=${USE_CPP11_ABI} + + + +ifeq ($(USE_LAPACK), 1) + DEFINES += -DUSE_LAPACK + LAPACK_LIBS = -llapacke -llapack + #LAPACK_LIBS += -lblas -lgfortran +else + DEFINES += -DNO_LAPACK + LAPACK_LIBS = +endif + +# actually: boost libs... +BASIC_LIBS = -lboost_system${BOOST_SUFFIX} -lboost_filesystem${BOOST_SUFFIX} + +ifeq ($(USE_3D), 1) + GL_LIBS = -lX11 -lGL -lGLU -lfreetype -lfontconfig +else + GL_LIBS = +endif + +ifeq ($(USE_IOSTR), 1) + BASIC_LIBS += -lboost_iostreams${BOOST_SUFFIX} +endif + +ifeq ($(USE_BOOST_REGEX), 1) + BASIC_LIBS += -lboost_regex${BOOST_SUFFIX} +endif + +ifeq ($(USE_PY), 1) + PY_LIBS = -lboost_python${BOOST_SUFFIX} -lpython2.7 + PY_OBJS = obj/sqw_py.o +else + PY_LIBS = + PY_OBJS = +endif + +ifeq ($(USE_GIL), 1) + GIL_LIBS = -lpng #-ljpeg -ltiff +else + GIL_LIBS = +endif + +ifeq ($(USE_PLUGINS), 1) + DL_LIBS = -ldl +else + DL_LIBS = +endif + + +LIBS_TAZ = ${STD_LIBS} ${QT_LIB} ${BASIC_LIBS} ${GL_LIBS} ${PY_LIBS} ${GIL_LIBS} ${DL_LIBS} +LIBS_RESO = ${QWT_LIB} ${STD_LIBS} ${QT_LIB} ${BASIC_LIBS} ${LAPACK_LIBS} + + +# ----------------------------------------------------------------------------- + + +OBJ_COMMON = obj/log.o obj/debug.o obj/rand.o obj/linalg2.o \ + obj/spec_char.o obj/EllipseDlg.o + +OBJ_TAZ = obj/taz_main.o obj/taz.o obj/taz_crys.o \ + obj/taz_file.o obj/taz_export.o \ + obj/scattering_triangle.o obj/real_lattice.o \ + obj/proj_lattice.o \ + obj/tas_layout.o obj/tof_layout.o \ + obj/RecipParamDlg.o obj/RealParamDlg.o obj/GotoDlg.o obj/PowderDlg.o \ + obj/DispDlg.o \ + obj/SettingsDlg.o obj/DWDlg.o obj/DynPlaneDlg.o obj/FormfactorDlg.o \ + obj/FilePreviewDlg.o obj/AtomsDlg.o \ + obj/SpurionDlg.o obj/NeutronDlg.o \ + obj/crystalsys.o obj/formfact.o \ + obj/cn.o obj/pop.o obj/eck.o obj/viol.o obj/simple.o \ + obj/ResoDlg.o obj/loadinstr.o obj/recent.o obj/globals.o \ + obj/globals_qt.o obj/qthelper.o \ + obj/sqw.o obj/sqwbase.o obj/sqwfact.o ${PY_OBJS} obj/tasreso.o \ + obj/ConvoDlg.o obj/SqwParamDlg.o \ + obj/scanviewer.o obj/x3d.o obj/eval.o \ + obj/tlibs_ver.o obj/AboutDlg.o obj/convo_scan.o + +OBJ_MONTERESO = obj/montereso_res.o obj/montereso_res_main.o \ + obj/qthelper.o obj/globals.o obj/globals_qt.o + +OBJ_MONTECONVO = obj/log.o obj/debug.o obj/sqw.o obj/sqwbase.o \ + obj/sqwfact.o ${PY_OBJS} obj/cn.o obj/pop.o obj/eck.o obj/viol.o \ + obj/rand.o obj/tasreso.o obj/eval.o \ + obj/linalg2.o + +OBJ_CONVOFIT = obj/convofit.o obj/convo_scan.o obj/convo_model.o \ + obj/loadinstr.o obj/eval.o obj/gnuplot.o ${OBJ_MONTECONVO} \ + obj/globals.o +OBJ_CONVOSERIES = obj/scanseries.o obj/log.o obj/debug.o + +OBJ_RESO = obj/log.o obj/debug.o obj/rand.o \ + obj/spec_char.o obj/reso_res_main.o \ + obj/cn.o obj/pop.o obj/eck.o obj/viol.o obj/simple.o obj/ResoDlg.o \ + obj/linalg2.o obj/globals.o obj/globals_qt.o + +OBJ_SCANVIEWER = obj/scanviewer_main.o obj/scanviewer.o \ + obj/loadinstr.o obj/log.o obj/debug.o obj/qthelper.o \ + obj/globals.o obj/globals_qt.o + +OBJ_SGLIST = obj/sglist_main.o obj/SgListDlg.o obj/spacegroup.o obj/crystalsys.o \ + obj/log.o obj/debug.o obj/globals.o obj/globals_qt.o + +OBJ_GENTAB = obj/spacegroup_clp.o obj/gentab.o obj/crystalsys_noqt.o obj/log.o \ + obj/debug.o + +OBJ_SFACT = obj/sfact.o obj/spacegroup_clp.o obj/crystalsys_noqt.o obj/globals.o \ + obj/formfact.o obj/log.o obj/debug.o + + +ifeq ($(USE_3D), 1) + OBJ_TAZ += obj/gl.o obj/plotgl.o obj/recip3d.o obj/EllipseDlg3D.o +endif + +ifeq ($(USE_NET), 1) + OBJ_TAZ += obj/tcp.o obj/nicos.o obj/sics.o obj/taz_net.o \ + obj/SrvDlg.o obj/NetCacheDlg.o +else + OBJ_TAZ += obj/taz_nonet.o +endif + +OBJ_TAZ += obj/SgListDlg.o obj/spacegroup.o +#LIBS_TAZ += + + +# ----------------------------------------------------------------------------- + + +.PHONY: all clean #doc + +all: takin montereso monteconvo xmonteconvo posextract \ + scanviewer gentab sglist sfact convofit convoseries reso + + +takin: ${OBJ_COMMON} ${OBJ_TAZ} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/takin $+ ${LIBS_TAZ} ${LIBS_RESO} + ${STRIP} bin/takin + +montereso: ${OBJ_COMMON} ${OBJ_MONTERESO} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/montereso $+ \ + ${STD_LIBS} ${BASIC_LIBS} ${QT_LIB} ${QWT_LIB} ${LAPACK_LIBS} + ${STRIP} montereso + +monteconvo: ${OBJ_MONTECONVO} obj/globals.o obj/mconv_main.o + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/monteconvo $+ \ + ${STD_LIBS} ${BASIC_LIBS} ${QT_LIB} ${PY_LIBS} ${LAPACK_LIBS} ${DL_LIBS} + ${STRIP} monteconvo + +xmonteconvo: ${OBJ_MONTECONVO} obj/xmconv_main.o obj/ConvoDlg.o obj/qthelper.o \ + obj/globals.o obj/globals_qt.o obj/SqwParamDlg.o obj/convo_scan.o obj/loadinstr.o + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/xmonteconvo $+ \ + ${STD_LIBS} ${BASIC_LIBS} ${QT_LIB} ${QWT_LIB} \ + ${PY_LIBS} ${LAPACK_LIBS} ${DL_LIBS} + ${STRIP} xmonteconvo + +convofit: ${OBJ_CONVOFIT} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/convofit $+ \ + -lMinuit2 ${STD_LIBS} ${BASIC_LIBS} ${PY_LIBS} ${LAPACK_LIBS} ${DL_LIBS} + ${STRIP} convofit +convoseries: ${OBJ_CONVOSERIES} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/convoseries $+ ${BASIC_LIBS} ${STD_LIBS} + +posextract: obj/posextract.o obj/loadinstr.o obj/log.o obj/debug.o + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/posextract $+ ${STD_LIBS} ${BASIC_LIBS} + ${STRIP} posextract + +reso: ${OBJ_RESO} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/reso $+ \ + ${STD_LIBS} ${QT_LIB} ${BASIC_LIBS} ${LAPACK_LIBS} -lX11 + ${STRIP} reso + +scanviewer: ${OBJ_SCANVIEWER} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/scanviewer $+ \ + ${STD_LIBS} ${BASIC_LIBS} ${QT_LIB} ${QWT_LIB} + ${STRIP} scanviewer + +sglist: ${OBJ_SGLIST} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/sglist $+ \ + ${STD_LIBS} ${QT_LIB} ${BASIC_LIBS} + ${STRIP} sglist + +gentab: ${OBJ_GENTAB} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/gentab $+ \ + ${STD_LIBS} ${BASIC_LIBS} -lclipper-core + +sfact: ${OBJ_SFACT} + ${CC} ${FLAGS} ${LIB_DIRS} -o bin/sfact $+ \ + ${STD_LIBS} ${BASIC_LIBS} -lclipper-core + +doc: doc/takin.qhcp doc/takin.qhp doc/*.html + qcollectiongenerator doc/takin.qhcp -o doc/takin.qhc + cp -v doc/takin.qhc res/ + cp -v doc/takin.qch res/ + + +# ----------------------------------------------------------------------------- + + +obj/taz_main.o: tools/taz/taz_main.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz.o: tools/taz/taz.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz_crys.o: tools/taz/taz_crys.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz_net.o: tools/taz/taz_net.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz_nonet.o: tools/taz/taz_nonet.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz_file.o: tools/taz/taz_file.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/taz_export.o: tools/taz/taz_export.cpp tools/taz/taz.h + ${CC} ${FLAGS} -c -o $@ $< +obj/recip3d.o: tools/taz/recip3d.cpp tools/taz/recip3d.h + ${CC} ${FLAGS} -c -o $@ $< +obj/scattering_triangle.o: tools/taz/scattering_triangle.cpp tools/taz/scattering_triangle.h tlibs/math/lattice.h + ${CC} ${FLAGS} -c -o $@ $< +obj/real_lattice.o: tools/taz/real_lattice.cpp tools/taz/real_lattice.h tlibs/math/lattice.h + ${CC} ${FLAGS} -c -o $@ $< +obj/proj_lattice.o: tools/taz/proj_lattice.cpp tools/taz/proj_lattice.h tlibs/math/lattice.h + ${CC} ${FLAGS} -c -o $@ $< +obj/tas_layout.o: tools/taz/tas_layout.cpp tools/taz/tas_layout.h + ${CC} ${FLAGS} -c -o $@ $< +obj/tof_layout.o: tools/taz/tof_layout.cpp tools/taz/tof_layout.h + ${CC} ${FLAGS} -c -o $@ $< +obj/RecipParamDlg.o: dialogs/RecipParamDlg.cpp dialogs/RecipParamDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/RealParamDlg.o: dialogs/RealParamDlg.cpp dialogs/RealParamDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/GotoDlg.o: dialogs/GotoDlg.cpp dialogs/GotoDlg.h tlibs/math/lattice.h + ${CC} ${FLAGS} -c -o $@ $< +obj/AtomsDlg.o: dialogs/AtomsDlg.cpp dialogs/AtomsDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/SettingsDlg.o: dialogs/SettingsDlg.cpp dialogs/SettingsDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/globals.o: libs/globals.cpp libs/globals.h + ${CC} ${FLAGS} -c -o $@ $< +obj/globals_qt.o: libs/globals_qt.cpp libs/globals_qt.h + ${CC} ${FLAGS} -c -o $@ $< +obj/qthelper.o: libs/qthelper.cpp libs/qthelper.h + ${CC} ${FLAGS} -c -o $@ $< +obj/PowderDlg.o: dialogs/PowderDlg.cpp dialogs/PowderDlg.h tlibs/math/lattice.h + ${CC} ${FLAGS} -c -o $@ $< +obj/DispDlg.o: dialogs/DispDlg.cpp dialogs/DispDlg.h tlibs/math/nn.h + ${CC} ${FLAGS} -c -o $@ $< +obj/SpurionDlg.o: dialogs/SpurionDlg.cpp dialogs/SpurionDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/DWDlg.o: dialogs/DWDlg.cpp dialogs/DWDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/FilePreviewDlg.o: dialogs/FilePreviewDlg.cpp dialogs/FilePreviewDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/DynPlaneDlg.o: dialogs/DynPlaneDlg.cpp dialogs/DynPlaneDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/FormfactorDlg.o: dialogs/FormfactorDlg.cpp dialogs/FormfactorDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/NeutronDlg.o: dialogs/NeutronDlg.cpp dialogs/NeutronDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/SrvDlg.o: dialogs/SrvDlg.cpp dialogs/SrvDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/NetCacheDlg.o: dialogs/NetCacheDlg.cpp dialogs/NetCacheDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/nicos.o: tools/taz/nicos.cpp tools/taz/nicos.h + ${CC} ${FLAGS} -c -o $@ $< +obj/sics.o: tools/taz/sics.cpp tools/taz/sics.h + ${CC} ${FLAGS} -c -o $@ $< + +obj/tlibs_ver.o: tlibs/version.cpp tlibs/version.h + ${CC} ${FLAGS} -c -o $@ $< +obj/spec_char.o: tlibs/string/spec_char.cpp tlibs/string/spec_char.h + ${CC} ${FLAGS} -c -o $@ $< +obj/log.o: tlibs/log/log.cpp tlibs/log/log.h + ${CC} ${FLAGS} -c -o $@ $< +obj/debug.o: tlibs/log/debug.cpp tlibs/log/debug.h + ${CC} ${FLAGS} -c -o $@ $< +obj/tcp.o: tlibs/net/tcp.cpp tlibs/net/tcp.h + ${CC} ${FLAGS} -c -o $@ $< +obj/linalg2.o: tlibs/math/linalg2.cpp tlibs/math/linalg2.h tlibs/math/geo.h + ${CC} ${FLAGS} -c -o $@ $< +obj/spacegroup_clp.o: libs/spacegroups/spacegroup_clp.cpp libs/spacegroups/spacegroup_clp.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/spacegroup.o: libs/spacegroups/spacegroup.cpp libs/spacegroups/spacegroup.h + ${CC} ${FLAGS} -c -o $@ $< +obj/crystalsys.o: libs/spacegroups/crystalsys.cpp libs/spacegroups/crystalsys.h + ${CC} ${FLAGS} -c -o $@ $< +obj/formfact.o: libs/formfactors/formfact.cpp libs/formfactors/formfact.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/rand.o: tlibs/math/rand.cpp tlibs/math/rand.h + ${CC} ${FLAGS} -c -o $@ $< +obj/plotgl.o: libs/plotgl.cpp libs/plotgl.h + ${CC} ${FLAGS} -c -o $@ $< +obj/gl.o: tlibs/gfx/gl.cpp tlibs/gfx/gl.h + ${CC} ${FLAGS} -c -o $@ $< +obj/gnuplot.o: tlibs/gfx/gnuplot.cpp tlibs/gfx/gnuplot.h tlibs/gfx/gnuplot_impl.h + ${CC} ${FLAGS} -c -o $@ $< +obj/loadinstr.o: tlibs/file/loadinstr.cpp tlibs/file/loadinstr.h + ${CC} ${FLAGS} -c -o $@ $< +#obj/loadtxt.o: tlibs/old/loadtxt.cpp tlibs/old/loadtxt.h +# ${CC} ${FLAGS} -c -o $@ $< +obj/x3d.o: tlibs/file/x3d.cpp tlibs/file/x3d.h + ${CC} ${FLAGS} -c -o $@ $< +obj/recent.o: tlibs/file/recent.cpp tlibs/file/recent.h + ${CC} ${FLAGS} -c -o $@ $< +#obj/minuit.o: tlibs/fit/minuit.cpp tlibs/fit/minuit.h +# ${CC} ${FLAGS} -c -o $@ $< +obj/eval.o: tlibs/string/eval.cpp tlibs/string/eval.h tlibs/string/eval_impl.h + ${CC} ${FLAGS} -c -o $@ $< + +obj/cn.o: tools/res/cn.cpp tools/res/cn.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/pop.o: tools/res/pop.cpp tools/res/pop.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/eck.o: tools/res/eck.cpp tools/res/eck.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/viol.o: tools/res/viol.cpp tools/res/viol.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/simple.o: tools/res/simple.cpp tools/res/simple.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +#obj/ellipse.o: tools/res/ellipse.cpp tools/res/ellipse.h +# ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/ResoDlg.o: tools/res/ResoDlg.cpp tools/res/ResoDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/ConvoDlg.o: tools/monteconvo/ConvoDlg.cpp tools/monteconvo/ConvoDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/SqwParamDlg.o: tools/monteconvo/SqwParamDlg.cpp tools/monteconvo/SqwParamDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/EllipseDlg.o: dialogs/EllipseDlg.cpp dialogs/EllipseDlg.h + ${CC} ${FLAGS} -c -o $@ $< +obj/EllipseDlg3D.o: dialogs/EllipseDlg3D.cpp dialogs/EllipseDlg3D.h + ${CC} ${FLAGS} -c -o $@ $< + +obj/montereso_res.o: tools/montereso/res.cpp tools/montereso/res.h + ${CC} ${FLAGS} -c -o $@ $< +obj/montereso_res_main.o: tools/montereso/res_main.cpp + ${CC} ${FLAGS} -c -o $@ $< +obj/reso_res_main.o: tools/res/res_main.cpp + ${CC} ${FLAGS} -c -o $@ $< + +obj/mconv_main.o: tools/monteconvo/mconv_main.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/xmconv_main.o: tools/monteconvo/xmconv_main.cpp + ${CC} ${FLAGS} -c -o $@ $< +obj/sqw.o: tools/monteconvo/sqw.cpp tools/monteconvo/sqw.h tlibs/math/kd.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/sqwbase.o: tools/monteconvo/sqwbase.cpp tools/monteconvo/sqwbase.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/sqwfact.o: tools/monteconvo/sqwfactory.cpp tools/monteconvo/sqwfactory.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/sqw_py.o: tools/monteconvo/sqw_py.cpp tools/monteconvo/sqw_py.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/tasreso.o: tools/monteconvo/TASReso.cpp tools/monteconvo/TASReso.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/posextract.o: tools/posextract/posextract.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< + +obj/convofit.o: tools/convofit/convofit.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/convo_scan.o: tools/convofit/scan.cpp tools/convofit/scan.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/convo_model.o: tools/convofit/model.cpp tools/convofit/model.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/scanseries.o: tools/convofit/scanseries.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< + +obj/scanviewer_main.o: tools/scanviewer/main.cpp + ${CC} ${FLAGS} -c -o $@ $< +obj/scanviewer.o: tools/scanviewer/scanviewer.cpp tools/scanviewer/scanviewer.h + ${CC} ${FLAGS} -c -o $@ $< + +obj/gentab.o: tools/gentab/gentab.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< + +obj/sglist_main.o: tools/sglist/main.cpp + ${CC} ${FLAGS} -c -o $@ $< +obj/SgListDlg.o: tools/sglist/SgListDlg.cpp tools/sglist/SgListDlg.h + ${CC} ${FLAGS} -c -o $@ $< + +obj/crystalsys_noqt.o: libs/spacegroups/crystalsys.cpp libs/spacegroups/crystalsys.h + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< +obj/sfact.o: tools/sggen/sfact.cpp + ${CC} ${FLAGS} -DNO_QT -c -o $@ $< + +obj/AboutDlg.o: dialogs/AboutDlg.cpp dialogs/AboutDlg.h + ${CC} ${FLAGS} -c -o $@ $< + + +# ----------------------------------------------------------------------------- + + +clean: + find bin -regex 'bin/[_a-zA-Z0-9]*' | xargs rm -f + rm -f bin/*.exe + rm -f obj/*.o + rm -f ui/*.h + rm -f *.moc + rm -f tools/taz/*.moc + rm -f tools/res/*.moc + rm -f tools/scanviewer/*.moc + rm -f tools/monteconvo/*.moc + rm -f tools/sglist/*.moc + rm -f dialogs/*.moc diff --git a/tlibs b/tlibs index 5276938..64f6a3a 160000 --- a/tlibs +++ b/tlibs @@ -1 +1 @@ -Subproject commit 52769388e9218ab372eb0b464188f8551b0817a3 +Subproject commit 64f6a3a320f3965ca06ecda4ff2388c253e3c741 diff --git a/tools/cli/cli_main.cpp b/tools/cli/cli_main.cpp new file mode 100644 index 0000000..1c44e68 --- /dev/null +++ b/tools/cli/cli_main.cpp @@ -0,0 +1,296 @@ +/** + * Minimalistic takin command line client + * @author tweber + * @date apr-2016 + * @license GPLv2 + */ + +#include "tlibs/log/log.h" +#include "tlibs/string/string.h" +#include "libs/version.h" +#include "tools/monteconvo/TASReso.h" + +#include +#include + +namespace ublas = boost::numeric::ublas; + +std::istream& istr = std::cin; +std::ostream& ostr = std::cout; + +using t_real = t_real_reso; +template using t_map = std::/*unordered_*/map; +using t_mat = ublas::matrix; +using t_vec = ublas::vector; + + +// ---------------------------------------------------------------------------- +// client function declarations +void show_help(const std::vector& vecArgs); +void load_sample(const std::vector& vecArgs); +void load_instr(const std::vector& vecArgs); +void fix(const std::vector& vecArgs); +void calc(const std::vector& vecArgs); +// ---------------------------------------------------------------------------- + + + +// ---------------------------------------------------------------------------- +// globals +TASReso g_tas; + +using t_func = void(*)(const std::vector&); +using t_funcmap = t_map; + +t_funcmap g_funcmap = +{ + {"help", &show_help}, + {"load_sample", &load_sample}, + {"load_instr", &load_instr}, + {"fix", &fix}, + {"calc", &calc}, +}; +// ---------------------------------------------------------------------------- + + + +// ---------------------------------------------------------------------------- +// client functions +void show_help(const std::vector& vecArgs) +{ + std::string strHelp = "Available client functions: "; + + for(t_funcmap::const_iterator iter=g_funcmap.begin(); iter!=g_funcmap.end(); ++iter) + { + const t_funcmap::value_type& pair = *iter; + strHelp += pair.first; + if(std::next(iter) != g_funcmap.end()) + strHelp += ", "; + } + + ostr << strHelp << ".\n"; +} + +void load_sample(const std::vector& vecArgs) +{ + if(vecArgs.size() < 2) + { + ostr << "Error: No filename given.\n"; + return; + } + + if(g_tas.LoadLattice(vecArgs[1].c_str())) + ostr << "OK.\n"; + else + ostr << "Error: Unable to load " << vecArgs[1] << ".\n"; +} + +void load_instr(const std::vector& vecArgs) +{ + if(vecArgs.size() < 2) + { + ostr << "Error: No filename given.\n"; + return; + } + + if(g_tas.LoadRes(vecArgs[1].c_str())) + ostr << "OK.\n"; + else + ostr << "Error: Unable to load " << vecArgs[1] << ".\n"; +} + +void fix(const std::vector& vecArgs) +{ + if(vecArgs.size() < 3) + { + ostr << "Error: No variable or value given.\n"; + return; + } + + if(vecArgs[1] == "ki") + g_tas.SetKiFix(1); + else if(vecArgs[1] == "kf") + g_tas.SetKiFix(0); + else + { + ostr << "Error: Unknown variable " << vecArgs[1] << ".\n"; + return; + } + + const t_real dVal = tl::str_to_var(vecArgs[2]); + g_tas.SetKFix(dVal); + ostr << "OK.\n"; +} + +std::ostream& operator<<(std::ostream& ostr, const t_mat& m) +{ + for(std::size_t i=0; i& vecArgs) +{ + if(vecArgs.size() < 5) + { + ostr << "Error: No hkl and E position given.\n"; + return; + } + + const t_real dH = tl::str_to_var(vecArgs[1]); + const t_real dK = tl::str_to_var(vecArgs[2]); + const t_real dL = tl::str_to_var(vecArgs[3]); + const t_real dE = tl::str_to_var(vecArgs[4]); + + const ResoResults& res = g_tas.GetResoResults(); + + g_tas.GetResoParams().bCalcR0 = 1; + //g_tas.GetTofResoParams().bCalcR0 = 1; + + if(!g_tas.SetHKLE(dH, dK, dL, dE)) + { + ostr << "Error: At postion Q=(" + << dH << "," << dK << "," << dL + << "), E=" << dE << ": " << res.strErr + << ".\n"; + return; + } + + //Ellipsoid4d ell4d = calc_res_ellipsoid4d(res.reso, res.Q_avg); + + int iParams[2][4][5] = + { + { // projected + {0, 3, 1, 2, -1}, + {1, 3, 0, 2, -1}, + {2, 3, 0, 1, -1}, + {0, 1, 3, 2, -1} + }, + { // sliced + {0, 3, -1, 2, 1}, + {1, 3, -1, 2, 0}, + {2, 3, -1, 1, 0}, + {0, 1, -1, 2, 3} + } + }; + + + ostr << "OK.\n"; + + ostr << "Reso: " << res.reso << "\n"; + ostr << "R0: " << res.dR0 << "\n"; + ostr << "Vol: " << res.dResVol << "\n"; + ostr << "Q_avg: " << res.Q_avg << "\n"; + ostr << "Bragg_FWHMs: " << res.dBraggFWHMs[0] << " " + << res.dBraggFWHMs[1] << " " + << res.dBraggFWHMs[2] << " " + << res.dBraggFWHMs[3] << "\n"; + + + std::vector>> tasks_ell_proj, tasks_ell_slice; + + for(unsigned int iEll=0; iEll<4; ++iEll) + { + const int *iP = iParams[0][iEll]; + const int *iS = iParams[1][iEll]; + + const t_vec& Q_avg = res.Q_avg; + const t_mat& reso = res.reso; + const t_vec& reso_v = res.reso_v; + const t_real& reso_s = res.reso_s; + + std::future> ell_proj = + std::async(std::launch::deferred|std::launch::async, + [=, &reso, &Q_avg]() + { return ::calc_res_ellipse( + reso, reso_v, reso_s, + Q_avg, iP[0], iP[1], iP[2], iP[3], iP[4]); }); + std::future> ell_slice = + std::async(std::launch::deferred|std::launch::async, + [=, &reso, &Q_avg]() + { return ::calc_res_ellipse( + reso, reso_v, reso_s, + Q_avg, iS[0], iS[1], iS[2], iS[3], iS[4]); }); + + tasks_ell_proj.push_back(std::move(ell_proj)); + tasks_ell_slice.push_back(std::move(ell_slice)); + } + for(unsigned int iEll=0; iEll<4; ++iEll) + { + Ellipse2d elliProj = tasks_ell_proj[iEll].get(); + Ellipse2d elliSlice = tasks_ell_slice[iEll].get(); + const std::string& strLabX = ::ellipse_labels(iParams[0][iEll][0], EllipseCoordSys::Q_AVG); + const std::string& strLabY = ::ellipse_labels(iParams[0][iEll][1], EllipseCoordSys::Q_AVG); + + ostr << "Ellipse_" << iEll << "_labels: " << strLabX << ", " << strLabY << "\n"; + + ostr << "Ellipse_" << iEll << "_proj_angle: " << elliProj.phi << "\n"; + ostr << "Ellipse_" << iEll << "_proj_HWHMs: " << elliProj.x_hwhm << " " << elliProj.y_hwhm << "\n"; + ostr << "Ellipse_" << iEll << "_proj_offs: " << elliProj.x_offs << " " << elliProj.y_offs << "\n"; + //ostr << "Ellipse_" << iEll << "_proj_area: " << elliProj.area << "\n"; + + ostr << "Ellipse_" << iEll << "_slice_angle: " << elliSlice.phi << "\n"; + ostr << "Ellipse_" << iEll << "_slice_HWHMs: " << elliSlice.x_hwhm << " " << elliSlice.y_hwhm << "\n"; + ostr << "Ellipse_" << iEll << "_slice_offs: " << elliSlice.x_offs << " " << elliSlice.y_offs << "\n"; + //ostr << "Ellipse_" << iEll << "_slice_area: " << elliSlice.area << "\n"; + } + + ostr.flush(); +} +// ---------------------------------------------------------------------------- + + + + + +// ---------------------------------------------------------------------------- +int main() +{ + tl::log_info("This is Takin-CLI, version " TAKIN_VER + " (built on " __DATE__ ")."); + tl::log_info("Please report bugs to tobias.weber@tum.de."); + + std::string strLine; + while(std::getline(istr, strLine)) + { + std::vector vecToks; + tl::get_tokens + (strLine, " \t", vecToks); + + for(std::string& strTok : vecToks) + tl::trim(strTok); + + if(!vecToks.size()) continue; + + if(vecToks[0] == "exit") + break; + + t_funcmap::const_iterator iter = g_funcmap.find(vecToks[0]); + if(iter == g_funcmap.end()) + { + ostr << "Error: No such function: " + << vecToks[0] << ".\n" << std::endl; + continue; + } + + (*iter->second)(vecToks); + ostr << "\n"; + } + + return 0; +} +// ---------------------------------------------------------------------------- diff --git a/tools/convofit/convofit.cpp b/tools/convofit/convofit.cpp new file mode 100644 index 0000000..6d4f0d9 --- /dev/null +++ b/tools/convofit/convofit.cpp @@ -0,0 +1,631 @@ +/** + * Convolution fitting + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#include "tlibs/file/prop.h" +#include "tlibs/file/loaddat.h" +#include "tlibs/log/log.h" +#include "tlibs/log/debug.h" +#include "tlibs/helper/thread.h" +#include "tlibs/gfx/gnuplot.h" +//#include "tlibs/math/neutrons.h" +#include "libs/version.h" + +#include +#include +#include + +#include +#include +#include + +#include "convofit.h" +#include "scan.h" +#include "model.h" +#include "../monteconvo/sqwfactory.h" +#include "../res/defs.h" + +//using t_real = tl::t_real_min; +using t_real = t_real_reso; + +namespace asio = boost::asio; +namespace sys = boost::system; + + +bool run_job(const std::string& strJob) +{ + // Parameters + tl::Prop prop; + if(!prop.Load(strJob.c_str(), tl::PropType::INFO)) + { + tl::log_err("Cannot load job file \"", strJob, "\"."); + return 0; + } + + std::string strScFile = prop.Query("input/scan_file"); + if(strScFile == "") // "scan_file_0" is synonymous to "scan_file" + strScFile = prop.Query("input/scan_file_0"); + + std::string strTempCol = prop.Query("input/temp_col"); + std::string strFieldCol = prop.Query("input/field_col"); + bool bTempOverride = prop.Exists("input/temp_override"); + bool bFieldOverride = prop.Exists("input/field_override"); + t_real dTempOverride = prop.QueryAndParse("input/temp_override"); + t_real dFieldOverride = prop.QueryAndParse("input/field_override"); + std::string strCntCol = prop.Query("input/counts_col"); + std::string strMonCol = prop.Query("input/monitor_col"); + + std::string strResFile = prop.Query("input/instrument_file"); + if(strResFile == "") // "instrument_file_0" is synonymous to "instrument_file" + strResFile = prop.Query("input/instrument_file_0"); + + std::string strSqwMod = prop.Query("input/sqw_model"); + std::string strSqwFile = prop.Query("input/sqw_file"); + std::string strTempVar = prop.Query("input/sqw_temp_var", "T"); + std::string strFieldVar = prop.Query("input/sqw_field_var", ""); + std::string strSetParams = prop.Query("input/sqw_set_params", ""); + bool bNormToMon = prop.Query("input/norm_to_monitor", 1); + + Filter filter; + filter.bLower = prop.Exists("input/filter_lower"); + filter.bUpper = prop.Exists("input/filter_upper"); + if(filter.bLower) filter.dLower = prop.QueryAndParse("input/filter_lower", 0); + if(filter.bUpper) filter.dUpper = prop.QueryAndParse("input/filter_upper", 0); + + + // -------------------------------------------------------------------- + // files in inner vector will be merged + // files in outer vector will be used for multi-function fitting + std::vector> vecvecScFiles; + + // primary scan files + { + std::vector vecScFiles; + tl::get_tokens(strScFile, ";", vecScFiles); + std::for_each(vecScFiles.begin(), vecScFiles.end(), [](std::string& str){ tl::trim(str); }); + vecvecScFiles.emplace_back(std::move(vecScFiles)); + } + + // get secondary scan files for multi-function fitting + for(std::size_t iSecFile=1; 1; ++iSecFile) + { + std::string strSecFile = "input/scan_file_" + tl::var_to_str(iSecFile); + std::string strSecScFile = prop.Query(strSecFile, ""); + if(strSecScFile == "") + break; + + std::vector vecSecScFiles; + tl::get_tokens(strSecScFile, ";", vecSecScFiles); + std::for_each(vecSecScFiles.begin(), vecSecScFiles.end(), [](std::string& str){ tl::trim(str); }); + vecvecScFiles.emplace_back(std::move(vecSecScFiles)); + } + // -------------------------------------------------------------------- + + + // -------------------------------------------------------------------- + //primary resolution file + std::vector vecResFiles({strResFile}); + + // get secondary resolution files for multi-function fitting + for(std::size_t iSecFile=1; 1; ++iSecFile) + { + std::string strSecFile = "input/instrument_file_" + tl::var_to_str(iSecFile); + std::string strSecResFile = prop.Query(strSecFile, ""); + if(strSecResFile == "") + break; + tl::trim(strSecResFile); + vecResFiles.emplace_back(std::move(strSecResFile)); + } + + if(vecResFiles.size()!=1 && vecResFiles.size()!=vecvecScFiles.size()) + { + tl::log_err("Number of resolution files has to be either one or match the number of scan files."); + tl::log_err("Number of scan files: ", vecvecScFiles.size(), ", number of resolution files: ", vecResFiles.size(), "."); + return 0; + } + // -------------------------------------------------------------------- + + + unsigned iNumNeutrons = prop.Query("montecarlo/neutrons", 1000); + + std::string strResAlgo = prop.Query("resolution/algorithm", "pop"); + bool bUseR0 = prop.Query("resolution/use_r0", 0); + bool bResFocMonoV = prop.Query("resolution/focus_mono_v", 0); + bool bResFocMonoH = prop.Query("resolution/focus_mono_h", 0); + bool bResFocAnaV = prop.Query("resolution/focus_ana_v", 0); + bool bResFocAnaH = prop.Query("resolution/focus_ana_h", 0); + + std::string strMinimiser = prop.Query("fitter/minimiser"); + int iStrat = prop.Query("fitter/strategy", 0); + t_real dSigma = prop.Query("fitter/sigma", 1.); + + bool bDoFit = prop.Query("fitter/do_fit", 1); + unsigned int iMaxFuncCalls = prop.Query("fitter/max_funccalls", 0); + t_real dTolerance = prop.Query("fitter/tolerance", 0.5); + + std::string strScOutFile = prop.Query("output/scan_file"); + std::string strModOutFile = prop.Query("output/model_file"); + std::string strLogOutFile = prop.Query("output/log_file"); + bool bPlot = prop.Query("output/plot", 0); + bool bPlotIntermediate = prop.Query("output/plot_intermediate", 0); + unsigned int iPlotPoints = prop.Query("output/plot_points", 128); + + std::unique_ptr> plt; + if(bPlot || bPlotIntermediate) + { + plt.reset(new tl::GnuPlot()); + plt->Init(); + } + + // thread-local debug log + std::unique_ptr ofstrLog; + if(strLogOutFile != "") + { + ofstrLog.reset(new std::ofstream(strLogOutFile)); + + for(tl::Log* plog : { &tl::log_info, &tl::log_warn, &tl::log_err, &tl::log_crit, &tl::log_debug }) + plog->AddOstr(ofstrLog.get(), 0, 1); + } + + if(strScOutFile=="" || strModOutFile=="") + { + tl::log_err("Not output files selected."); + return 0; + } + + + std::string strFitParams = prop.Query("fit_parameters/params"); + std::string strFitValues = prop.Query("fit_parameters/values"); + std::string strFitErrors = prop.Query("fit_parameters/errors"); + std::string strFitFixed = prop.Query("fit_parameters/fixed"); + + std::vector vecFitParams; + tl::get_tokens(strFitParams, " \t\n,;", vecFitParams); + std::vector vecFitValues; + tl::parse_tokens(strFitValues, " \t\n,;", vecFitValues); + std::vector vecFitErrors; + tl::parse_tokens(strFitErrors, " \t\n,;", vecFitErrors); + std::vector vecFitFixed; + tl::get_tokens(strFitFixed, " \t\n,;", vecFitFixed); + + if(vecFitParams.size() != vecFitValues.size() || + vecFitParams.size() != vecFitErrors.size() || + vecFitParams.size() != vecFitFixed.size()) + { + tl::log_err("Fit parameter size mismatch."); + return 0; + } + + + + + // -------------------------------------------------------------------- + // Scan files + std::vector vecSc; + for(std::size_t iSc=0; iSc 1) + tl::log_info("Loading scan group ", iSc, "."); + if(!load_file(vecvecScFiles[iSc], sc, bNormToMon, filter)) + { + tl::log_err("Cannot load scan files of group ", iSc, "."); + continue; + } + + vecSc.emplace_back(std::move(sc)); + } + if(!vecSc.size()) + { + tl::log_err("No scans loaded."); + return 0; + } + + tl::log_info("Number of scan groups: ", vecSc.size(), "."); + + // scan plot object + tl::PlotObj pltMeas; + if(bPlot || bPlotIntermediate) + { + pltMeas.vecX = vecSc[0].vecX; + pltMeas.vecY = vecSc[0].vecCts; + pltMeas.vecErrY = vecSc[0].vecCtsErr; + pltMeas.linestyle = tl::STYLE_POINTS; + } + // -------------------------------------------------------------------- + + + + + // -------------------------------------------------------------------- + // Resolution files + std::vector vecResos; + for(const std::string& strCurResFile : vecResFiles) + { + TASReso reso; + tl::log_info("Loading instrument resolution file \"", strCurResFile, "\"."); + if(!reso.LoadRes(strCurResFile.c_str())) + return 0; + + if(strResAlgo == "pop") + reso.SetAlgo(ResoAlgo::POP); + else if(strResAlgo == "cn") + reso.SetAlgo(ResoAlgo::CN); + else if(strResAlgo == "eck") + reso.SetAlgo(ResoAlgo::ECK); + else if(strResAlgo == "viol") + reso.SetAlgo(ResoAlgo::VIOL); + else + { + tl::log_err("Invalid resolution algorithm selected: \"", strResAlgo, "\"."); + return 0; + } + + if(bResFocMonoV || bResFocMonoH || bResFocAnaV || bResFocAnaH) + { + unsigned iFoc = 0; + if(bResFocMonoV) iFoc |= unsigned(ResoFocus::FOC_MONO_V); + if(bResFocMonoH) iFoc |= unsigned(ResoFocus::FOC_MONO_H); + if(bResFocAnaV) iFoc |= unsigned(ResoFocus::FOC_ANA_V); + if(bResFocAnaH) iFoc |= unsigned(ResoFocus::FOC_ANA_H); + + reso.SetOptimalFocus(ResoFocus(iFoc)); + } + + if(bUseR0 && !reso.GetResoParams().bCalcR0) + tl::log_warn("Resolution R0 requested, but not calculated, using raw ellipsoid volume."); + + vecResos.emplace_back(std::move(reso)); + } + + // base parameter set for single-fits + set_tasreso_params_from_scan(vecResos[0], vecSc[0]); + // -------------------------------------------------------------------- + + + + + // -------------------------------------------------------------------- + // Model file + tl::log_info("Loading S(q,w) file \"", strSqwFile, "\"."); + std::shared_ptr pSqw = construct_sqw(strSqwMod, strSqwFile); + + if(!pSqw) + { + tl::log_err("Invalid S(q,w) model selected: \"", strSqwMod, "\"."); + return 0; + } + + if(!pSqw->IsOk()) + { + tl::log_err("S(q,w) model cannot be initialised."); + return 0; + } + SqwFuncModel mod(pSqw, vecResos); + + + std::vector vecModTmpX, vecModTmpY; + // slots + mod.AddFuncResultSlot( + [&plt, &pltMeas, &vecModTmpX, &vecModTmpY, bPlotIntermediate](t_real h, t_real k, t_real l, t_real E, t_real S) + { + tl::log_info("Q = (", h, ", ", k, ", ", l, ") rlu, E = ", E, " meV -> S = ", S); + + if(bPlotIntermediate) + { + vecModTmpX.push_back(E); // TODO: use scan direction + vecModTmpY.push_back(S); + + tl::PlotObj pltMod; + pltMod.vecX = vecModTmpX; + pltMod.vecY = vecModTmpY; + pltMod.linestyle = tl::STYLE_LINES_SOLID; + pltMod.odSize = 1.5; + + plt->StartPlot(); + plt->SetYLabel("Intensity"); + plt->AddLine(pltMod); + plt->AddLine(pltMeas); + plt->FinishPlot(); + } + }); + mod.AddParamsChangedSlot( + [&vecModTmpX, &vecModTmpY, bPlotIntermediate](const std::string& strDescr) + { + tl::log_info("Changed model parameters: ", strDescr); + + if(bPlotIntermediate) + { + vecModTmpX.clear(); + vecModTmpY.clear(); + } + }); + + + // only needed for multi-fits + if(vecSc.size() > 1) + mod.SetScans(&vecSc); + + mod.SetNumNeutrons(iNumNeutrons); + mod.SetUseR0(bUseR0); + + if(bTempOverride) + { + for(Scan& sc : vecSc) + { + sc.dTemp = dTempOverride; + sc.dTempErr = 0.; + } + } + if(bFieldOverride) + { + for(Scan& sc : vecSc) + { + sc.dField = dFieldOverride; + sc.dFieldErr = 0.; + } + } + mod.SetOtherParamNames(strTempVar, strFieldVar); + + // base parameter set for single-fits + set_model_params_from_scan(mod, vecSc[0]); + + tl::log_info("Model temperature variable: \"", strTempVar, "\", value: ", vecSc[0].dTemp); + tl::log_info("Model field variable: \"", strFieldVar, "\", value: ", vecSc[0].dField); + + + // set given individual model parameters + if(strSetParams != "") + { + std::vector vecSetParams; + tl::get_tokens(strSetParams, ";", vecSetParams); + for(const std::string& strModParam : vecSetParams) + { + std::vector vecModParam; + tl::get_tokens(strModParam, "=", vecModParam); + if(vecModParam.size() < 2) + continue; + tl::trim(vecModParam[0]); + tl::trim(vecModParam[1]); + + if(mod.GetSqwBase()->SetVarIfAvail(vecModParam[0], vecModParam[1])) + tl::log_info("Setting model parameter \"", vecModParam[0], "\" to \"", vecModParam[1], "\"."); + else + tl::log_err("No parameter named \"", vecModParam[0], "\" available in S(q,w) model."); + } + } + // -------------------------------------------------------------------- + + + + + // -------------------------------------------------------------------- + // Fitting + for(std::size_t iParam=0; iParam chi2fkt(&mod, vecSc[0].vecX.size(), vecSc[0].vecX.data(), vecSc[0].vecCts.data(), vecSc[0].vecCtsErr.data()); + tl::Chi2Function_mult chi2fkt; + // the vecSc[0] data sets are the default data set (will not be used if scan groups are defined) + chi2fkt.AddFunc(&mod, vecSc[0].vecX.size(), vecSc[0].vecX.data(), vecSc[0].vecCts.data(), vecSc[0].vecCtsErr.data()); + chi2fkt.SetDebug(1); + chi2fkt.SetSigma(dSigma); + + + minuit::MnUserParameters params = mod.GetMinuitParams(); + for(std::size_t iParam=0; iParam pmini; + if(strMinimiser == "simplex") + pmini.reset(new minuit::MnSimplex(chi2fkt, params, strat)); + else if(strMinimiser == "migrad") + pmini.reset(new minuit::MnMigrad(chi2fkt, params, strat)); + else + { + tl::log_err("Invalid minimiser selected: \"", strMinimiser, "\"."); + return 0; + } + + bool bValidFit = 0; + if(bDoFit) + { + tl::log_info("Performing fit."); + minuit::FunctionMinimum mini = (*pmini)(iMaxFuncCalls, dTolerance); + const minuit::MnUserParameterState& state = mini.UserState(); + bValidFit = mini.IsValid() && mini.HasValidParameters() && state.IsValid(); + mod.SetMinuitParams(state); + + std::ostringstream ostrMini; + ostrMini << mini << "\n"; + tl::log_info(ostrMini.str(), "Fit valid: ", bValidFit); + } + else + { + tl::log_info("Skipping fit, keeping initial values."); + } + + + tl::log_info("Saving results."); + + for(std::size_t iSc=0; iSc 1) + { + strCurModOutFile += tl::var_to_str(iSc); + strCurScOutFile += tl::var_to_str(iSc); + } + std::pair xminmax + = std::minmax_element(sc.vecX.begin(), sc.vecX.end()); + mod.Save(strCurModOutFile.c_str(), *xminmax.first, *xminmax.second, iPlotPoints); + save_file(strCurScOutFile.c_str(), sc); + } + // -------------------------------------------------------------------- + + + + + // -------------------------------------------------------------------- + // Plotting + if(bPlot) + { + /*std::ostringstream ostr; + ostr << "gnuplot -p -e \"plot \\\"" + << strModOutFile.c_str() << "\\\" using 1:2 w lines lw 1.5 lt 1, \\\"" + << strScOutFile.c_str() << "\\\" using 1:2:3 w yerrorbars ps 1 pt 7\"\n"; + std::system(ostr.str().c_str());*/ + + tl::DatFile datMod; + datMod.Load(strModOutFile); + + tl::PlotObj pltMod; + pltMod.vecX = datMod.GetColumn(0); + pltMod.vecY = datMod.GetColumn(1); + pltMod.linestyle = tl::STYLE_LINES_SOLID; + pltMod.odSize = 1.5; + + plt->StartPlot(); + plt->SetYLabel("Intensity"); + plt->AddLine(pltMod); + plt->AddLine(pltMeas); + plt->FinishPlot(); + } + // -------------------------------------------------------------------- + + + + + // remove thread-local loggers + if(!!ofstrLog) + { + for(tl::Log* plog : { &tl::log_info, &tl::log_warn, &tl::log_err, &tl::log_crit, &tl::log_debug }) + plog->RemoveOstr(ofstrLog.get()); + } + + return bValidFit; +} + + + + +int main(int argc, char** argv) +{ + // plain C locale + std::setlocale(LC_ALL, "C"); + std::locale::global(std::locale::classic()); + + // install exit signal handlers + asio::io_service ioSrv; + asio::signal_set sigInt(ioSrv, SIGABRT, SIGTERM, SIGINT); + sigInt.async_wait([&ioSrv](const sys::error_code& err, int iSig) + { + tl::log_warn("Hard exit requested via signal ", iSig, ". This may cause a fault."); + if(err) tl::log_err("Error: ", err.message(), ", error category: ", err.category().name(), "."); + ioSrv.stop(); +#ifdef SIGKILL + std::raise(SIGKILL); +#endif + exit(-1); + }); + std::thread thSig([&ioSrv]() { ioSrv.run(); }); + BOOST_SCOPE_EXIT(&ioSrv, &thSig) + { + //tl::log_debug("Exiting..."); + ioSrv.stop(); + thSig.join(); + } + BOOST_SCOPE_EXIT_END + + + tl::log_info("This is the Takin command-line convolution fitter, version " TAKIN_VER "."); + tl::log_info("Written by Tobias Weber , 2014-2016."); + tl::log_debug("Resolution calculation uses ", sizeof(t_real_reso)*8, " bit ", tl::get_typename(), "s."); + tl::log_debug("Fitting uses ", sizeof(tl::t_real_min)*8, " bit ", tl::get_typename(), "s."); + + if(argc > 2) + { + for(tl::Log* log : { &tl::log_info, &tl::log_warn, &tl::log_err, &tl::log_crit, &tl::log_debug }) + log->SetShowThread(1); + } + + if(argc <= 1) + { + tl::log_info("Usage:"); + tl::log_info("\t", argv[0], " ..."); + return -1; + } + + + unsigned int iNumThreads = std::thread::hardware_concurrency(); + tl::ThreadPool tp(iNumThreads); + + for(int iArg=1; iArg bool + { + tl::log_info("Executing job file ", iArg, ": \"", strJob, "\"."); + + return run_job(strJob); + //if(argc > 2) tl::log_info("================================================================================"); + }); + } + + tp.StartTasks(); + + auto& lstFut = tp.GetFutures(); + unsigned int iTask = 1; + for(auto& fut : lstFut) + { + bool bOk = fut.get(); + if(!bOk) + tl::log_err("Job ", iTask, " (", argv[iTask], ") failed or fit invalid!"); + ++iTask; + } + + return 0; +} diff --git a/tools/convofit/convofit.h b/tools/convofit/convofit.h new file mode 100644 index 0000000..ba968de --- /dev/null +++ b/tools/convofit/convofit.h @@ -0,0 +1,35 @@ +/** + * Convolution fitting + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#ifndef __TAKIN_CONVOFIT_H__ +#define __TAKIN_CONVOFIT_H__ + +#include "scan.h" +#include "model.h" + + +static inline void set_tasreso_params_from_scan(TASReso& reso, const Scan& sc) +{ + reso.SetLattice(sc.sample.a, sc.sample.b, sc.sample.c, + sc.sample.alpha, sc.sample.beta, sc.sample.gamma, + tl::make_vec({sc.plane.vec1[0], sc.plane.vec1[1], sc.plane.vec1[2]}), + tl::make_vec({sc.plane.vec2[0], sc.plane.vec2[1], sc.plane.vec2[2]})); + reso.SetKiFix(sc.bKiFixed); + reso.SetKFix(sc.dKFix); +} + +static inline void set_model_params_from_scan(SqwFuncModel& mod, const Scan& sc) +{ + mod.SetScanOrigin(sc.vecScanOrigin[0], sc.vecScanOrigin[1], + sc.vecScanOrigin[2], sc.vecScanOrigin[3]); + mod.SetScanDir(sc.vecScanDir[0], sc.vecScanDir[1], + sc.vecScanDir[2], sc.vecScanDir[3]); + + mod.SetOtherParams(sc.dTemp, sc.dField); +} + +#endif diff --git a/tools/convofit/model.cpp b/tools/convofit/model.cpp new file mode 100644 index 0000000..66b1ea4 --- /dev/null +++ b/tools/convofit/model.cpp @@ -0,0 +1,369 @@ +/** + * Convolution fitting model + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#include + +#include "model.h" +#include "tlibs/log/log.h" +#include "tlibs/string/string.h" +#include "tlibs/helper/array.h" +#include "../res/defs.h" +#include "convofit.h" + +using t_real = t_real_mod; + + +SqwFuncModel::SqwFuncModel(std::shared_ptr pSqw, const TASReso& reso) + : m_pSqw(pSqw)/*, m_reso(reso)*/, m_vecResos({reso}) +{} + +SqwFuncModel::SqwFuncModel(std::shared_ptr pSqw, const std::vector& vecResos) + : m_pSqw(pSqw), m_vecResos(vecResos) +{} + + +tl::t_real_min SqwFuncModel::operator()(tl::t_real_min x) const +{ + //TASReso reso = m_reso; + TASReso reso; + // multi-fits + if(m_pScans && m_vecResos.size() > 1) + reso = m_vecResos[m_iCurParamSet]; + else + reso = m_vecResos[0]; + const ublas::vector vecScanPos = m_vecScanOrigin + t_real(x)*m_vecScanDir; + + if(!reso.SetHKLE(vecScanPos[0],vecScanPos[1],vecScanPos[2],vecScanPos[3])) + { + std::ostringstream ostrErr; + ostrErr << "Invalid crystal position: (" + << vecScanPos[0] << " " << vecScanPos[1] << " " << vecScanPos[2] + << ") rlu, " << vecScanPos[3] << " meV."; + //throw tl::Err(ostrErr.str().c_str()); + tl::log_err(ostrErr.str()); + return 0.; + } + + + std::vector> vecNeutrons; + Ellipsoid4d elli = reso.GenerateMC(m_iNumNeutrons, vecNeutrons); + + t_real dS = 0.; + t_real dhklE_mean[4] = {0., 0., 0., 0.}; + + for(const ublas::vector& vecHKLE : vecNeutrons) + { + dS += t_real((*m_pSqw)(vecHKLE[0], vecHKLE[1], vecHKLE[2], vecHKLE[3])); + + for(int i=0; i<4; ++i) + dhklE_mean[i] += t_real(vecHKLE[i]); + } + + dS /= t_real(m_iNumNeutrons); + for(int i=0; i<4; ++i) + dhklE_mean[i] /= t_real(m_iNumNeutrons); + + if(m_bUseR0) + dS *= reso.GetResoResults().dResVol; + if(m_bUseR0 && reso.GetResoParams().bCalcR0) + dS *= reso.GetResoResults().dR0; + + if(m_psigFuncResult) + { + (*m_psigFuncResult)(vecScanPos[0], vecScanPos[1], vecScanPos[2], vecScanPos[3], + dS*m_dScale + m_dOffs); + } + return tl::t_real_min(dS*m_dScale + m_dOffs); +} + +SqwFuncModel* SqwFuncModel::copy() const +{ + // cannot rebuild kd tree in phonon model with only a shallow copy + SqwFuncModel* pMod = new SqwFuncModel( + std::shared_ptr(m_pSqw->shallow_copy())/*, m_reso*/, m_vecResos); + pMod->m_vecScanOrigin = this->m_vecScanOrigin; + pMod->m_vecScanDir = this->m_vecScanDir; + pMod->m_iNumNeutrons = this->m_iNumNeutrons; + pMod->m_dScale = this->m_dScale; + pMod->m_dOffs = this->m_dOffs; + pMod->m_dScaleErr = this->m_dScaleErr; + pMod->m_dOffsErr = this->m_dOffsErr; + pMod->m_vecModelParamNames = this->m_vecModelParamNames; + pMod->m_vecModelParams = this->m_vecModelParams; + pMod->m_vecModelErrs = this->m_vecModelErrs; + pMod->m_strTempParamName = this->m_strTempParamName; + pMod->m_strFieldParamName = this->m_strFieldParamName; + pMod->m_bUseR0 = this->m_bUseR0; + pMod->m_iCurParamSet = this->m_iCurParamSet; + pMod->m_pScans = this->m_pScans; + pMod->m_psigFuncResult = this->m_psigFuncResult; + pMod->m_psigParamsChanged = this->m_psigParamsChanged; + + return pMod; +} + +void SqwFuncModel::SetOtherParamNames(std::string strTemp, std::string strField) +{ + m_strTempParamName = strTemp; + m_strFieldParamName = strField; +} + +void SqwFuncModel::SetOtherParams(t_real dTemperature, t_real dField) +{ + std::vector vecVars; + if(m_strTempParamName != "") + vecVars.push_back(std::make_tuple(m_strTempParamName, "double", tl::var_to_str(dTemperature))); + if(m_strFieldParamName != "") + vecVars.push_back(std::make_tuple(m_strFieldParamName, "double", tl::var_to_str(dField))); + m_pSqw->SetVars(vecVars); +} + +void SqwFuncModel::SetModelParams() +{ + const std::size_t iNumParams = m_vecModelParams.size(); + std::vector vecVars; + vecVars.reserve(iNumParams); + + for(std::size_t iParam=0; iParamSetVars(vecVars); +} + +bool SqwFuncModel::SetParams(const std::vector& vecParams) +{ + // -------------------------------------------------------------------- + // prints changed model parameters + std::vector vecOldParams = {m_dScale, m_dOffs}; + vecOldParams.insert(vecOldParams.end(), m_vecModelParams.begin(), m_vecModelParams.end()); + std::vector vecParamNames = GetParamNames(); + if(vecOldParams.size()==vecParams.size() && vecParamNames.size()==vecParams.size()) + { + std::ostringstream ostrDebug; + std::transform(vecParams.begin(), vecParams.end(), vecParamNames.begin(), + std::ostream_iterator(ostrDebug, ", "), + [&vecOldParams, &vecParamNames](tl::t_real_min _dVal, const std::string& strParam) -> std::string + { + t_real dVal = t_real(_dVal); + std::vector::const_iterator iterParam = + std::find(vecParamNames.begin(), vecParamNames.end(), strParam); + if(iterParam == vecParamNames.end()) + return ""; + t_real dOldParam = vecOldParams[iterParam-vecParamNames.begin()]; + + bool bChanged = !tl::float_equal(dVal, dOldParam); + std::string strRet = strParam + + std::string(" = ") + + tl::var_to_str(dVal); + if(bChanged) + strRet += " (old: " + tl::var_to_str(dOldParam) + ")"; + return strRet; + }); + + if(m_psigParamsChanged) + (*m_psigParamsChanged)(ostrDebug.str()); + } + // -------------------------------------------------------------------- + + m_dScale = t_real(vecParams[0]); + m_dOffs = t_real(vecParams[1]); + + for(std::size_t iParam=2; iParam& vecErrs) +{ + m_dScaleErr = t_real(vecErrs[0]); + m_dOffsErr = t_real(vecErrs[1]); + + for(std::size_t iParam=2; iParam SqwFuncModel::GetParamNames() const +{ + std::vector vecNames = {"scale", "offs"}; + + for(const std::string& str : m_vecModelParamNames) + vecNames.push_back(str); + + return vecNames; +} + +std::vector SqwFuncModel::GetParamValues() const +{ + std::vector vecVals = {m_dScale, m_dOffs}; + + for(t_real d : m_vecModelParams) + vecVals.push_back(tl::t_real_min(d)); + + return vecVals; +} + +std::vector SqwFuncModel::GetParamErrors() const +{ + std::vector vecErrs = {m_dScaleErr, m_dOffsErr}; + + for(t_real d : m_vecModelErrs) + vecErrs.push_back(tl::t_real_min(d)); + + return vecErrs; +} + +void SqwFuncModel::SetMinuitParams(const minuit::MnUserParameters& state) +{ + std::vector vecNewVals; + std::vector vecNewErrs; + + const std::vector vecNames = GetParamNames(); + for(std::size_t iParam=0; iParam()(vecNewVals)); + SetErrs(tl::container_cast()(vecNewErrs)); +} + +minuit::MnUserParameters SqwFuncModel::GetMinuitParams() const +{ + minuit::MnUserParameters params; + + params.Add("scale", m_dScale, m_dScaleErr); + params.Add("offs", m_dOffs, m_dOffsErr); + + for(std::size_t iParam=0; iParam vecNames = GetParamNames(); + + tl::container_cast cst; + const std::vector vecVals = cst(GetParamValues()); + const std::vector vecErrs = cst(GetParamErrors()); + + for(std::size_t iParam=0; iParam= m_pScans->size()) + { + tl::log_err("Requested invalid scan group ", iSet); + return; + } + + if(m_iCurParamSet != iSet) + { + m_iCurParamSet = iSet; + + const Scan& sc = m_pScans->operator[](m_iCurParamSet); + if(m_vecResos.size() > 1) + set_tasreso_params_from_scan(m_vecResos[m_iCurParamSet], sc); + else + set_tasreso_params_from_scan(/*m_reso*/ m_vecResos[0], sc); + set_model_params_from_scan(*this, sc); + } +} + +std::size_t SqwFuncModel::GetParamSetCount() const +{ + // multi-fits + if(m_pScans) + return m_pScans->size(); + + // single-fits + return 1; +} + +std::size_t SqwFuncModel::GetExpLen() const +{ + if(m_pScans) + return m_pScans->operator[](m_iCurParamSet).vecX.size(); + return 0; +} + +const t_real_mod* SqwFuncModel::GetExpX() const +{ + if(m_pScans) + return m_pScans->operator[](m_iCurParamSet).vecX.data(); + return nullptr; +} + +const t_real_mod* SqwFuncModel::GetExpY() const +{ + if(m_pScans) + return m_pScans->operator[](m_iCurParamSet).vecCts.data(); + return nullptr; +} + +const t_real_mod* SqwFuncModel::GetExpDY() const +{ + if(m_pScans) + return m_pScans->operator[](m_iCurParamSet).vecCtsErr.data(); + return nullptr; +} +// ----------------------------------------------------------------------------- diff --git a/tools/convofit/model.h b/tools/convofit/model.h new file mode 100644 index 0000000..18cb6ce --- /dev/null +++ b/tools/convofit/model.h @@ -0,0 +1,149 @@ +/** + * Convolution fitting model + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#ifndef __CONVOFIT_MOD_H__ +#define __CONVOFIT_MOD_H__ + +#include +#include +#include + +#include "tlibs/fit/minuit.h" +#include +#include +#include +#include + +#include + +#include "../monteconvo/sqwbase.h" +#include "../monteconvo/TASReso.h" +#include "../res/defs.h" +#include "scan.h" + +namespace minuit = ROOT::Minuit2; +namespace sig = boost::signals2; + +//using t_real_mod = tl::t_real_min; +using t_real_mod = t_real_reso; + + +class SqwFuncModel : public tl::MinuitMultiFuncModel +{ +protected: + std::shared_ptr m_pSqw; + std::vector m_vecResos; + //TASReso m_reso; + unsigned int m_iNumNeutrons = 1000; + + ublas::vector m_vecScanOrigin; // hklE + ublas::vector m_vecScanDir; // hklE + + t_real_mod m_dScale = 1., m_dOffs = 0.; + t_real_mod m_dScaleErr = 0.1, m_dOffsErr = 0.; + + std::vector m_vecModelParamNames; + std::vector m_vecModelParams; + std::vector m_vecModelErrs; + + std::string m_strTempParamName = "T"; + std::string m_strFieldParamName = ""; + + bool m_bUseR0 = false; + + // ------------------------------------------------------------------------- + // optional, for multi-fits + std::size_t m_iCurParamSet = 0; + const std::vector* m_pScans = nullptr; + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // signals + public: using t_sigFuncResult = sig::signal; + protected: std::shared_ptr m_psigFuncResult; + public: void AddFuncResultSlot(const t_sigFuncResult::slot_type& slot) + { + if(!m_psigFuncResult) m_psigFuncResult = std::make_shared(); + m_psigFuncResult->connect(slot); + } + + public: using t_sigParamsChanged = sig::signal; + protected: std::shared_ptr m_psigParamsChanged; + public: void AddParamsChangedSlot(const t_sigParamsChanged::slot_type& slot) + { + if(!m_psigParamsChanged) m_psigParamsChanged = std::make_shared(); + m_psigParamsChanged->connect(slot); + } + // ------------------------------------------------------------------------- + +protected: + void SetModelParams(); + +public: + SqwFuncModel(std::shared_ptr pSqw, const TASReso& reso); + SqwFuncModel(std::shared_ptr pSqw, const std::vector& vecResos); + SqwFuncModel() = delete; + virtual ~SqwFuncModel() = default; + + virtual bool SetParams(const std::vector& vecParams) override; + virtual bool SetErrs(const std::vector& vecErrs); + virtual tl::t_real_min operator()(tl::t_real_min x) const override; + + virtual SqwFuncModel* copy() const override; + + virtual const char* GetModelName() const override { return "SqwFuncModel"; } + virtual std::vector GetParamNames() const override; + virtual std::vector GetParamValues() const override; + virtual std::vector GetParamErrors() const override; + + // ------------------------------------------------------------------------- + // optional, for multi-fits + virtual void SetParamSet(std::size_t iSet) override; + virtual std::size_t GetParamSetCount() const override; + virtual std::size_t GetExpLen() const override; + virtual const t_real_mod* GetExpX() const override; + virtual const t_real_mod* GetExpY() const override; + virtual const t_real_mod* GetExpDY() const override; + + void SetScans(const std::vector* pScans) { m_pScans = pScans; } + // ------------------------------------------------------------------------- + + + void SetOtherParamNames(std::string strTemp, std::string strField); + void SetOtherParams(t_real_mod dTemperature, t_real_mod dField); + + void SetReso(const TASReso& reso) { /*m_reso = reso;*/ m_vecResos = {reso}; } + void SetResos(const std::vector& vecResos) { m_vecResos = vecResos; } + void SetNumNeutrons(unsigned int iNum) { m_iNumNeutrons = iNum; } + + void SetScanOrigin(t_real_mod h, t_real_mod k, t_real_mod l, t_real_mod E) + { m_vecScanOrigin = tl::make_vec({h,k,l,E}); } + void SetScanDir(t_real_mod h, t_real_mod k, t_real_mod l, t_real_mod E) + { m_vecScanDir = tl::make_vec({h,k,l,E}); } + + void AddModelFitParams(const std::string& strName, t_real_mod dInitValue=0., t_real_mod dErr=0.) + { + m_vecModelParamNames.push_back(strName); + m_vecModelParams.push_back(dInitValue); + m_vecModelErrs.push_back(dErr); + } + + minuit::MnUserParameters GetMinuitParams() const; + void SetMinuitParams(const minuit::MnUserParameters& params); + void SetMinuitParams(const minuit::MnUserParameterState& state) + { SetMinuitParams(state.Parameters()); } + + bool Save(const char *pcFile, t_real_mod dXMin, t_real_mod dXMax, std::size_t) const; + + void SetUseR0(bool bR0) { m_bUseR0 = bR0; } + + SqwBase* GetSqwBase() { return m_pSqw.get(); } +}; + + +#endif diff --git a/tools/convofit/scan.cpp b/tools/convofit/scan.cpp new file mode 100644 index 0000000..e753eb1 --- /dev/null +++ b/tools/convofit/scan.cpp @@ -0,0 +1,276 @@ +/** + * Convolution fitting + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#include "scan.h" +#include "tlibs/log/log.h" + +#include + + +bool save_file(const char* pcFile, const Scan& sc) +{ + std::ofstream ofstr(pcFile); + if(!ofstr) + return false; + + ofstr.precision(16); + + ofstr << "# scan_origin = " + << sc.vecScanOrigin[0] << " " + << sc.vecScanOrigin[1] << " " + << sc.vecScanOrigin[2] << " " + << sc.vecScanOrigin[3] << "\n"; + ofstr << "# scan_dir = " + << sc.vecScanDir[0] << " " + << sc.vecScanDir[1] << " " + << sc.vecScanDir[2] << " " + << sc.vecScanDir[3] << "\n"; + ofstr << "# T = " << sc.dTemp << " +- " << sc.dTempErr << "\n"; + ofstr << "# B = " << sc.dField << " +- " << sc.dFieldErr << "\n"; + + ofstr << "#\n"; + + ofstr << std::left << std::setw(21) << "# x" + << std::left << std::setw(21) << "counts" + << std::left << std::setw(21) << "count errors" + << std::left << std::setw(21) << "monitor" + << std::left << std::setw(21) << "monitor errors" << "\n"; + + const std::size_t iNum = sc.vecX.size(); + for(std::size_t i=0; i& vecFiles, Scan& scan, bool bNormToMon, const Filter& filter) +{ + if(!vecFiles.size()) return 0; + tl::log_info("Loading \"", vecFiles[0], "\"."); + + std::unique_ptr> pInstr(tl::FileInstrBase::LoadInstr(vecFiles[0].c_str())); + if(!pInstr) + { + tl::log_err("Cannot load \"", vecFiles[0], "\"."); + return false; + } + + for(std::size_t iFile=1; iFile> pInstrM(tl::FileInstrBase::LoadInstr(vecFiles[iFile].c_str())); + if(!pInstrM) + { + tl::log_err("Cannot load \"", vecFiles[iFile], "\"."); + continue; + } + + pInstr->MergeWith(pInstrM.get()); + } + + + std::string strCountVar = pInstr->GetCountVar(); // defaults + std::string strMonVar = pInstr->GetMonVar(); + if(scan.strCntCol != "") strCountVar = scan.strCntCol; // overrides + if(scan.strMonCol != "") strMonVar = scan.strMonCol; + tl::log_info("Counts column: ", strCountVar, "\nMonitor column: ", strMonVar); + + scan.vecCts = pInstr->GetCol(strCountVar); + scan.vecMon = pInstr->GetCol(strMonVar); + + std::function funcErr = [](t_real_sc d) -> t_real_sc + { + //if(tl::float_equal(d, 0.)) // error 0 causes problems with minuit + // return d/100.; + return std::sqrt(d); + }; + scan.vecCtsErr = tl::apply_fkt(scan.vecCts, funcErr); + scan.vecMonErr = tl::apply_fkt(scan.vecMon, funcErr); + + if(bNormToMon) + { + for(std::size_t iPos=0; iPos latt = pInstr->GetSampleLattice(); + const std::array ang = pInstr->GetSampleAngles(); + + scan.sample.a = latt[0]; scan.sample.b = latt[1]; scan.sample.c = latt[2]; + scan.sample.alpha = ang[0]; scan.sample.beta = ang[1]; scan.sample.gamma = ang[2]; + + tl::log_info("Sample lattice: ", scan.sample.a, " ", scan.sample.b, " ", scan.sample.c); + tl::log_info("Sample angles: ", tl::r2d(scan.sample.alpha), " ", tl::r2d(scan.sample.beta), " ", tl::r2d(scan.sample.gamma)); + + + const std::array vec1 = pInstr->GetScatterPlane0(); + const std::array vec2 = pInstr->GetScatterPlane1(); + scan.plane.vec1[0] = vec1[0]; scan.plane.vec1[1] = vec1[1]; scan.plane.vec1[2] = vec1[2]; + scan.plane.vec2[0] = vec2[0]; scan.plane.vec2[1] = vec2[1]; scan.plane.vec2[2] = vec2[2]; + + tl::log_info("Scattering plane: [", vec1[0], vec1[1], vec1[2], "], " + "[", vec2[0], vec2[1], vec2[2], "]"); + + + scan.bKiFixed = pInstr->IsKiFixed(); + scan.dKFix = pInstr->GetKFix(); + if(scan.bKiFixed) + tl::log_info("ki = ", scan.dKFix); + else + tl::log_info("kf = ", scan.dKFix); + + + const tl::FileInstrBase::t_vecVals& vecTemp = pInstr->GetCol(scan.strTempCol); + if(vecTemp.size() == 0) + { + tl::log_warn("Sample temperature column \"", scan.strTempCol, "\" not found."); + //return false; + } + else + { + scan.dTemp = tl::mean_value(vecTemp); + scan.dTempErr = tl::std_dev(vecTemp); + tl::log_info("Sample temperature: ", scan.dTemp, " +- ", scan.dTempErr); + } + + const tl::FileInstrBase::t_vecVals& vecField = pInstr->GetCol(scan.strFieldCol); + if(vecField.size() == 0) + { + tl::log_warn("Sample field column \"", scan.strFieldCol, "\" not found."); + //return false; + } + else + { + scan.dField = tl::mean_value(vecField); + scan.dFieldErr = tl::std_dev(vecField); + tl::log_info("Sample field: ", scan.dField, " +- ", scan.dFieldErr); + } + + + const std::size_t iNumPts = pInstr->GetScanCount(); + for(std::size_t iPt=0; iPt sc = pInstr->GetScanHKLKiKf(iPt); + + ScanPoint pt; + pt.h = sc[0]; pt.k = sc[1]; pt.l = sc[2]; + pt.ki = sc[3]/tl::get_one_angstrom(); + pt.kf = sc[4]/tl::get_one_angstrom(); + pt.Ei = tl::k2E(pt.ki); pt.Ef = tl::k2E(pt.kf); + pt.E = pt.Ei-pt.Ef; + + tl::log_info("Point ", iPt+1, ": ", "h=", pt.h, ", k=", pt.k, ", l=", pt.l, + ", ki=", t_real_sc(pt.ki*tl::get_one_angstrom()), + ", kf=", t_real_sc(pt.kf*tl::get_one_angstrom()), + ", E=", t_real_sc(pt.E/tl::get_one_meV())/*, ", Q=", pt.Q*tl::angstrom*/, + ", Cts=", scan.vecCts[iPt]/*, "+-", scan.vecCtsErr[iPt]*/, + ", Mon=", scan.vecMon[iPt]/*, "+-", scan.vecMonErr[iPt]*/); + + scan.vecPoints.emplace_back(std::move(pt)); + } + + + + const ScanPoint& ptBegin = *scan.vecPoints.cbegin(); + const ScanPoint& ptEnd = *scan.vecPoints.crbegin(); + + scan.vecScanOrigin[0] = ptBegin.h; + scan.vecScanOrigin[1] = ptBegin.k; + scan.vecScanOrigin[2] = ptBegin.l; + scan.vecScanOrigin[3] = ptBegin.E / tl::get_one_meV(); + + scan.vecScanDir[0] = ptEnd.h - ptBegin.h; + scan.vecScanDir[1] = ptEnd.k - ptBegin.k; + scan.vecScanDir[2] = ptEnd.l - ptBegin.l; + scan.vecScanDir[3] = (ptEnd.E - ptBegin.E) / tl::get_one_meV(); + + const t_real_sc dEps = 0.01; + + for(unsigned int i=0; i<4; ++i) + { + if(!tl::float_equal(scan.vecScanDir[i], 0., dEps)) + { + scan.vecScanDir[i] /= scan.vecScanDir[i]; + scan.vecScanOrigin[i] = 0.; + } + else + { + scan.vecScanDir[i] = 0.; + } + } + + tl::log_info("Scan origin: (", scan.vecScanOrigin[0], " ", scan.vecScanOrigin[1], " ", scan.vecScanOrigin[2], " ", scan.vecScanOrigin[3], ")"); + tl::log_info("Scan dir: [", scan.vecScanDir[0], " ", scan.vecScanDir[1], " ", scan.vecScanDir[2], " ", scan.vecScanDir[3], "]"); + + + + unsigned int iScIdx = 0; + for(iScIdx=0; iScIdx<4; ++iScIdx) + if(!tl::float_equal(scan.vecScanDir[iScIdx], 0., dEps)) + break; + + if(iScIdx >= 4) + { + tl::log_err("No scan variable found!"); + return false; + } + + for(std::size_t iPt=0; iPt() }; + scan.vecX.push_back(dPos[iScIdx]); + //tl::log_info("Added pos: ", *scan.vecX.rbegin()); + } + + + + // filter + decltype(scan.vecX) vecXNew; + decltype(scan.vecCts) vecCtsNew, vecMonNew, vecCtsErrNew, vecMonErrNew; + for(std::size_t i=0; i= filter.dUpper) continue; + + vecXNew.push_back(scan.vecX[i]); + vecCtsNew.push_back(scan.vecCts[i]); + vecMonNew.push_back(scan.vecMon[i]); + vecCtsErrNew.push_back(scan.vecCtsErr[i]); + vecMonErrNew.push_back(scan.vecMonErr[i]); + } + scan.vecX = std::move(vecXNew); + scan.vecCts = std::move(vecCtsNew); + scan.vecMon = std::move(vecMonNew); + scan.vecCtsErr = std::move(vecCtsErrNew); + scan.vecMonErr = std::move(vecMonErrNew); + + + return true; +} + +bool load_file(const char* pcFile, Scan& scan, bool bNormToMon, const Filter& filter) +{ + std::vector vec{pcFile}; + return load_file(vec, scan, bNormToMon, filter); +} diff --git a/tools/convofit/scan.h b/tools/convofit/scan.h new file mode 100644 index 0000000..b725a07 --- /dev/null +++ b/tools/convofit/scan.h @@ -0,0 +1,109 @@ +/** + * Convolution fitting + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#ifndef __CONVOFIT_SCAN_H__ +#define __CONVOFIT_SCAN_H__ + +#include +#include + +#include "tlibs/math/math.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/file/loadinstr.h" + +//#include "tlibs/fit/minuit.h" // only to get intrinsic real type +//using t_real_sc = tl::t_real_min; + +#include "../res/defs.h" +using t_real_sc = t_real_reso; + + +struct ScanPoint +{ + t_real_sc h, k, l; + tl::t_wavenumber_si ki, kf; + tl::t_energy_si Ei, Ef, E; +}; + +struct Sample +{ + t_real_sc a, b, c; + t_real_sc alpha, beta, gamma; +}; + +struct Plane +{ + t_real_sc vec1[3]; + t_real_sc vec2[3]; +}; + + +struct Filter +{ + bool bLower = 0; + bool bUpper = 0; + + t_real_sc dLower = 0.; + t_real_sc dUpper = 0.; +}; + + +struct Scan +{ + Sample sample; + Plane plane; + bool bKiFixed=0; + t_real_sc dKFix = 2.662; + + std::string strTempCol = "TT"; + t_real_sc dTemp = 100., dTempErr=0.; + + std::string strFieldCol = ""; + t_real_sc dField = 0., dFieldErr=0.; + + std::string strCntCol = ""; + std::string strMonCol = ""; + std::vector vecPoints; + + std::vector vecX; + std::vector vecCts, vecMon; + std::vector vecCtsErr, vecMonErr; + + t_real_sc vecScanOrigin[4]; + t_real_sc vecScanDir[4]; + + + ScanPoint InterpPoint(std::size_t i, std::size_t N) const + { + const ScanPoint& ptBegin = *vecPoints.cbegin(); + const ScanPoint& ptEnd = *vecPoints.crbegin(); + + ScanPoint pt; + + pt.h = tl::lerp(ptBegin.h, ptEnd.h, t_real_sc(i)/t_real_sc(N-1)); + pt.k = tl::lerp(ptBegin.k, ptEnd.k, t_real_sc(i)/t_real_sc(N-1)); + pt.l = tl::lerp(ptBegin.l, ptEnd.l, t_real_sc(i)/t_real_sc(N-1)); + pt.E = tl::lerp(ptBegin.E, ptEnd.E, t_real_sc(i)/t_real_sc(N-1)); + pt.Ei = tl::lerp(ptBegin.Ei, ptEnd.Ei, t_real_sc(i)/t_real_sc(N-1)); + pt.Ef = tl::lerp(ptBegin.Ef, ptEnd.Ef, t_real_sc(i)/t_real_sc(N-1)); + bool bImag=0; + pt.ki = tl::E2k(pt.Ei, bImag); + pt.kf = tl::E2k(pt.Ef, bImag); + + return pt; + } +}; + + +extern bool load_file(const std::vector& vecFiles, Scan& scan, + bool bNormToMon=1, const Filter& filter = Filter()); +extern bool load_file(const char* pcFile, Scan& scan, + bool bNormToMon=1, const Filter& filter=Filter()); +extern bool save_file(const char* pcFile, const Scan& sc); + + +#endif diff --git a/tools/convofit/scanseries.cpp b/tools/convofit/scanseries.cpp new file mode 100644 index 0000000..d70ffe3 --- /dev/null +++ b/tools/convofit/scanseries.cpp @@ -0,0 +1,161 @@ +// gcc -I../../ -o scanseries scanseries.cpp ../../tlibs/log/log.cpp -std=c++11 -lboost_system -lboost_filesystem -lstdc++ +/** + * processes multiple convo fit results + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include "tlibs/string/string.h" +#include "tlibs/file/file.h" +#include "tlibs/log/log.h" + + +using t_real = double; +using t_map = std::map>; + + +// reads property maps from data files +bool get_fileprops(const char* pcFile, t_map& mapProps) +{ + std::ifstream ifstr(pcFile); + if(!ifstr) + { + tl::log_err("Cannot open file \"", pcFile, "\"."); + return 0; + } + + std::string strLine; + while(std::getline(ifstr, strLine)) + { + tl::trim(strLine); + if(!strLine.size() || strLine[0] != '#') + continue; + + strLine = strLine.substr(1); + std::pair strKeyVal = + tl::split_first(strLine, std::string("="), 1); + + std::string& strKey = strKeyVal.first; + std::string& _strVal = strKeyVal.second; + + if(!strKey.size()) + continue; + + + std::vector vecHKLE; + tl::get_tokens(_strVal, std::string(" \t"), vecHKLE); + + // value & error pair + if(_strVal.find("+-") != std::string::npos) + { + std::pair strValErr = + tl::split_first(_strVal, std::string("+-"), 1, 1); + + std::string& strVal = strValErr.first; + std::string& strErr = strValErr.second; + + //std::cout << strKey << ": " << strVal << ", " << strErr << std::endl; + if(strVal.length()) + { + t_real dVal = tl::str_to_var(strVal); + t_real dErr = tl::str_to_var(strErr); + + mapProps.insert(t_map::value_type(strKey, {dVal, dErr})); + } + } + // hklE values -> split them, e.g. "scan_dir = 0 0 0 1" -> "scan_dir_h = 0", ... + else if(vecHKLE.size()==3 || vecHKLE.size()==4) + { + std::vector vecSuffixes = {"_h", "_k", "_l", "_E"}; + + std::size_t iNumCoords = std::min(vecSuffixes.size(), vecHKLE.size()); + for(unsigned int iCoord=0; iCoord ..." << std::endl; + std::cerr << "\te.g." << argv[0] << " out T TA2_E_HWHM TA2_amp" << std::endl; + return -1; + } + + std::string strOutDir = argv[1]; + + std::vector vecCols; + for(int iArg=2; iArgsecond.first << " "; + ofstr << std::left << std::setw(20) << iter->second.second << " "; + } + + ofstr << "\n"; + } + + tl::log_info("Wrote \"", strOut, "\"."); + return 0; +} diff --git a/tools/gentab/gentab.cpp b/tools/gentab/gentab.cpp new file mode 100644 index 0000000..19648c3 --- /dev/null +++ b/tools/gentab/gentab.cpp @@ -0,0 +1,456 @@ +/** + * Creates needed tables + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include + +#include "tlibs/string/string.h" +#include "tlibs/file/prop.h" +#include "tlibs/log/log.h" +#include "tlibs/math/linalg.h" +#include "libs/spacegroups/spacegroup_clp.h" + +#ifndef USE_BOOST_REX + #include + namespace rex = ::std; +#else + #include + namespace rex = ::boost; +#endif + +#include +#include + +namespace prop = boost::property_tree; +namespace algo = boost::algorithm; +namespace ublas = boost::numeric::ublas; + +using t_real = double; +using t_cplx = std::complex; +using t_mat = ublas::matrix; + + +unsigned g_iPrec = std::numeric_limits::max_digits10-1; + +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ugly, but can't be helped for the moment: +// directly link to the internal clipper coefficients table +// that lives in clipper/clipper/core/atomsf.cpp +namespace clipper { namespace data +{ + extern const struct SFData + { + const char atomname[8]; + const t_real a[5], c, b[5], d; // d is always 0 + } sfdata[]; + + const unsigned int numsfdata = 212; +}} +// ---------------------------------------------------------------------------- + +namespace dat = clipper::data; + + +bool gen_formfacts() +{ + tl::Prop prop; + prop.SetSeparator('.'); + + prop.Add("ffacts.source", "Form factor coefficients extracted from Clipper"); + prop.Add("ffacts.source_url", "http://www.ysbl.york.ac.uk/~cowtan/clipper/"); + prop.Add("ffacts.num_atoms", tl::var_to_str(dat::numsfdata)); + + for(unsigned int iFF=0; iFF(str, "(", ")"); + + if(tl::string_rm(str, "", "")) + { // complex number + std::size_t iSign = str.find_last_of("+-"); + str.insert(iSign, ", "); + str.insert(0, "("); + str.push_back(')'); + } + + tl::trim(str); + if(str == "---") str = ""; + + + t_cplx c; + std::istringstream istr(str); + istr >> c; + + t_real dR = c.real(), dI = c.imag(); + tl::set_eps_0(dR); tl::set_eps_0(dI); + c.real(dR); c.imag(dI); + return c; +} + +bool gen_scatlens() +{ + std::ifstream ifstr("tmp/scatlens.html"); + if(!ifstr) + { + tl::log_err("Cannot open \"tmp/scatlens.html\"."); + return false; + } + + bool bTableStarted = 0; + std::string strTable; + while(!ifstr.eof()) + { + std::string strLine; + std::getline(ifstr, strLine); + + if(!bTableStarted) + { + std::vector vecHdr; + tl::get_tokens_seq(strLine, "", vecHdr, 0); + if(vecHdr.size() < 9) + continue; + bTableStarted = 1; + } + else + { + // at end of table? + if(tl::str_to_lower(strLine).find("/table") != std::string::npos) + break; + + strTable += strLine; + } + } + ifstr.close(); + + + + std::vector vecRows; + tl::get_tokens_seq(strTable, "", vecRows, 0); + + + tl::Prop prop; + prop.SetSeparator('.'); + prop.Add("scatlens.source", "Scattering lengths and cross-sections extracted from NIST table"); + prop.Add("scatlens.source_url", "https://www.ncnr.nist.gov/resources/n-lengths/list.html"); + + unsigned int iAtom = 0; + for(const std::string& strRow : vecRows) + { + if(strRow.length() == 0) + continue; + + std::ostringstream ostr; + ostr << "scatlens.atom_" << iAtom; + std::string strAtom = ostr.str(); + + + std::vector vecCol; + tl::get_tokens_seq(strRow, "", vecCol, 0); + if(vecCol.size() < 9) + { + tl::log_warn("Invalid number of table entries in row \"", strRow, "\"."); + continue; + } + + std::string strName = vecCol[1]; + tl::trim(strName); + if(strName == "") continue; + + t_cplx cCoh = get_number(vecCol[3]); + t_cplx cIncoh = get_number(vecCol[4]); + t_real dXsecCoh = get_number(vecCol[5]).real(); + t_real dXsecIncoh = get_number(vecCol[6]).real(); + t_real dXsecScat = get_number(vecCol[7]).real(); + t_real dXsecAbsTherm = get_number(vecCol[8]).real(); + + prop.Add(strAtom + ".name", strName); + prop.Add(strAtom + ".coh", tl::var_to_str(cCoh, g_iPrec)); + prop.Add(strAtom + ".incoh", tl::var_to_str(cIncoh, g_iPrec)); + + prop.Add(strAtom + ".xsec_coh", tl::var_to_str(dXsecCoh, g_iPrec)); + prop.Add(strAtom + ".xsec_incoh", tl::var_to_str(dXsecIncoh, g_iPrec)); + prop.Add(strAtom + ".xsec_scat", tl::var_to_str(dXsecScat, g_iPrec)); + prop.Add(strAtom + ".xsec_abs", tl::var_to_str(dXsecAbsTherm, g_iPrec)); + + ++iAtom; + } + + prop.Add("scatlens.num_atoms", tl::var_to_str(iAtom)); + + + if(!prop.Save("res/scatlens.xml.gz")) + { + tl::log_err("Cannot write \"res/scatlens.xml.gz\"."); + return false; + } + return true; +} + + +// ============================================================================ + + +bool gen_spacegroups() +{ + tl::Prop prop; + prop.SetSeparator('.'); + + const unsigned int iNumSGs = 230; + prop.Add("sgroups.source", "Space group data extracted from Clipper"); + prop.Add("sgroups.source_url", "http://www.ysbl.york.ac.uk/~cowtan/clipper/"); + prop.Add("sgroups.num_groups", tl::var_to_str(iNumSGs)); + + for(unsigned int iSG=1; iSG<=iNumSGs; ++iSG) + { + SpaceGroupClp sg(iSG); + + std::ostringstream ostr; + ostr << "sgroups.group_" << (iSG-1); + std::string strGroup = ostr.str(); + + prop.Add(strGroup + ".number", tl::var_to_str(iSG)); + prop.Add(strGroup + ".name", sg.GetName()); + //prop.Add(strGroup + ".pointgroup", get_pointgroup(sg.GetName())); + prop.Add(strGroup + ".lauegroup", sg.GetLaueGroup()); + //prop.Add(strGroup + ".crystalsys", sg.GetCrystalSystem()); + //prop.Add(strGroup + ".crystalsysname", sg.GetCrystalSystemName()); + + + std::vector vecTrafos, vecInv, vecPrim, vecCenter; + sg.GetSymTrafos(vecTrafos); + sg.GetInvertingSymTrafos(vecInv); + sg.GetPrimitiveSymTrafos(vecPrim); + sg.GetCenteringSymTrafos(vecCenter); + + + prop.Add(strGroup + ".num_trafos", tl::var_to_str(vecTrafos.size())); + unsigned int iTrafo = 0; + for(const t_mat& matTrafo : vecTrafos) + { + bool bIsInv = is_mat_in_container(vecInv, matTrafo); + bool bIsPrim = is_mat_in_container(vecPrim, matTrafo); + bool bIsCenter = is_mat_in_container(vecCenter, matTrafo); + + std::string strOpts = "; "; + if(bIsPrim) strOpts += "p"; + if(bIsInv) strOpts += "i"; + if(bIsCenter) strOpts += "c"; + + std::ostringstream ostrTrafo; + ostrTrafo << strGroup << ".trafo_" << iTrafo; + std::string strTrafo = ostrTrafo.str(); + + prop.Add(strTrafo, tl::var_to_str(matTrafo, g_iPrec) + strOpts); + + ++iTrafo; + } + } + + + if(!prop.Save("res/sgroups.xml.gz")) + { + tl::log_err("Cannot write \"res/sgroups.xml.gz\"."); + return false; + } + + return true; +} + + +// ============================================================================ + + +bool gen_magformfacts() +{ + tl::Prop propOut; + propOut.SetSeparator('.'); + propOut.Add("magffacts.source", "Magnetic form factor coefficients extracted from ILL table"); + propOut.Add("magffacts.source_url", "https://www.ill.eu/sites/ccsl/ffacts/"); + + std::size_t iAtom=0; + std::set setAtoms; + + std::vector vecFiles = + {"tmp/j0_1.html", "tmp/j0_2.html", + "tmp/j0_3.html" , "tmp/j0_4.html", + + "tmp/j2_1.html", "tmp/j2_2.html", + "tmp/j2_3.html", "tmp/j2_4.html",}; + + for(std::size_t iFile=0; iFile rex("<([A-Za-z]*)[A-Za-z0-9\\=\\\"\\ ]*>", rex::regex::ECMAScript); + strTable = rex::regex_replace(strTable, rex, "<$1>"); + + tl::find_all_and_replace(strTable, "

", ""); + tl::find_all_and_replace(strTable, "

", ""); + //std::cout << strTable << std::endl; + + + std::istringstream istrTab(strTable); + tl::Prop prop; + prop.Load(istrTab, tl::PropType::XML); + const auto& tab = prop.GetProp().begin()->second; + + auto iter = tab.begin(); ++iter; + for(; iter!=tab.end(); ++iter) + { + auto iterElem = iter->second.begin(); + std::string strElem = iterElem++->second.data(); + tl::trim(strElem); + if(*strElem.rbegin() == '0') + strElem.resize(strElem.length()-1); + else + strElem += "+"; + + if(setAtoms.find(strElem) != setAtoms.end()) + { + tl::log_warn("Atom ", strElem, " already in set. Ignoring."); + continue; + } + setAtoms.insert(strElem); + + t_real dA = tl::str_to_var(iterElem++->second.data()); + t_real da = tl::str_to_var(iterElem++->second.data()); + t_real dB = tl::str_to_var(iterElem++->second.data()); + t_real db = tl::str_to_var(iterElem++->second.data()); + t_real dC = tl::str_to_var(iterElem++->second.data()); + t_real dc = tl::str_to_var(iterElem++->second.data()); + t_real dD = tl::str_to_var(iterElem->second.data()); + + std::ostringstream ostrAtom; + ostrAtom << "magffacts." + strJ + ".atom_" << iAtom; + propOut.Add(ostrAtom.str() + ".name", strElem); + propOut.Add(ostrAtom.str() + ".A", tl::var_to_str(dA, g_iPrec)); + propOut.Add(ostrAtom.str() + ".a", tl::var_to_str(da, g_iPrec)); + propOut.Add(ostrAtom.str() + ".B", tl::var_to_str(dB, g_iPrec)); + propOut.Add(ostrAtom.str() + ".b", tl::var_to_str(db, g_iPrec)); + propOut.Add(ostrAtom.str() + ".C", tl::var_to_str(dC, g_iPrec)); + propOut.Add(ostrAtom.str() + ".c", tl::var_to_str(dc, g_iPrec)); + propOut.Add(ostrAtom.str() + ".D", tl::var_to_str(dD, g_iPrec)); + ++iAtom; + } + } + + propOut.Add("magffacts.num_atoms", tl::var_to_str(iAtom)); + + if(!propOut.Save("res/magffacts.xml.gz")) + { + tl::log_err("Cannot write \"res/magffacts.xml.gz\"."); + return false; + } + + return true; +} + + +// ============================================================================ + + +int main() +{ + std::cout << "Generating atomic form factor coefficient table ... "; + if(gen_formfacts()) + std::cout << "OK" << std::endl; + + std::cout << "Generating scattering length table ... "; + if(gen_scatlens()) + std::cout << "OK" << std::endl; + + std::cout << "Generating space group table ... "; + if(gen_spacegroups()) + std::cout << "OK" << std::endl; + + std::cout << "Generating magnetic form factor coefficient table ... "; + if(gen_magformfacts()) + std::cout << "OK" << std::endl; + + return 0; +} diff --git a/tools/mini_scanmon/dialog.cpp b/tools/mini_scanmon/dialog.cpp new file mode 100644 index 0000000..b5579bd --- /dev/null +++ b/tools/mini_scanmon/dialog.cpp @@ -0,0 +1,56 @@ +// gcc -o dialog dialog.cpp -std=c++11 -lstdc++ -ldialog + +#include "dialog.h" +#include

+#include +#include + + +static void *g_pProgress = nullptr; +std::string g_strTitle; + + +bool open_progress(const std::string& strTitle) +{ + g_strTitle = strTitle; + close_progress(); + + init_dialog(stdin, stdout); + dlg_clear(); + + g_pProgress = dlg_allocate_gauge(g_strTitle.c_str(), "", 10, 50, 0); + if(g_pProgress) + return true; + return false; +} + +void close_progress() +{ + if(g_pProgress) + { + dlg_free_gauge(g_pProgress); + g_pProgress = nullptr; + } + end_dialog(); +} + +void set_progress(int iPerc, const std::string& strTxt) +{ + if(!g_pProgress) return; + + g_pProgress = dlg_reallocate_gauge(g_pProgress, g_strTitle.c_str(), strTxt.c_str(), 10, 50, iPerc); + dlg_update_gauge(g_pProgress, iPerc); +} + + +/*int main(int argc, char** argv) +{ + open_progress("Test"); + set_progress(10, "abc\ndef\nghi"); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + set_progress(20, "xyz\n123\n456"); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + close_progress(); + return 0; +}*/ diff --git a/tools/mini_scanmon/dialog.h b/tools/mini_scanmon/dialog.h new file mode 100644 index 0000000..a005f33 --- /dev/null +++ b/tools/mini_scanmon/dialog.h @@ -0,0 +1,10 @@ +#ifndef __DIALOG_H__ +#define __DIALOG_H__ + +#include + +extern bool open_progress(const std::string& strTitle); +extern void close_progress(); +extern void set_progress(int iPerc, const std::string& strTxt); + +#endif diff --git a/tools/mini_scanmon/dialog_indirect.cpp b/tools/mini_scanmon/dialog_indirect.cpp new file mode 100644 index 0000000..403ade9 --- /dev/null +++ b/tools/mini_scanmon/dialog_indirect.cpp @@ -0,0 +1,63 @@ +// gcc -o dialog dialog_indirect.cpp -std=c++11 -lstdc++ -lboost_iostreams + +#include "dialog.h" +#include +#include +#include +#include + +namespace ios = boost::iostreams; + + +static FILE *pipeProg = nullptr; +static boost::iostreams::file_descriptor_sink *pfds = nullptr; +static boost::iostreams::stream_buffer *psbuf = nullptr; +static std::ostream *postrProg = nullptr; + +bool open_progress(const std::string& strTitle) +{ + close_progress(); + + pipeProg = (FILE*)popen(("dialog --title \"" + strTitle + "\" --gauge \"\" 10 50 0").c_str(), "w"); + if(!pipeProg) return false; + pfds = new ios::file_descriptor_sink(fileno(pipeProg), ios::close_handle); + psbuf = new ios::stream_buffer(*pfds); + postrProg = new std::ostream(psbuf); + + return true; +} + +void close_progress() +{ + if(pipeProg) + { + pclose(pipeProg); + pipeProg = nullptr; + } + + if(postrProg) { delete postrProg; postrProg = nullptr; } + if(psbuf) { delete psbuf; psbuf = nullptr; } + if(pfds) { delete pfds; pfds = nullptr; } +} + +void set_progress(int iPerc, const std::string& strTxt) +{ + if(!postrProg) return; + (*postrProg) << "XXX\n" << iPerc << "\n" + << strTxt << "\nXXX" + << std::endl; +} + + +/*int main(int argc, char** argv) +{ + open_progress("Test"); + set_progress(10, "abc\ndef\nghi"); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + set_progress(20, "xyz\n123\n456"); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + close_progress(); + return 0; +}*/ + diff --git a/tools/mini_scanmon/mini_scanmon.cpp b/tools/mini_scanmon/mini_scanmon.cpp new file mode 100644 index 0000000..db9328b --- /dev/null +++ b/tools/mini_scanmon/mini_scanmon.cpp @@ -0,0 +1,194 @@ +/* + * mini scan monitor + * @author tweber + * @date 2015 + * @license GPLv2 + * + * clang -O2 -o mini_scanmon mini_scanmon.cpp dialog_indirect.cpp ../../tlibs/net/tcp.cpp ../../tlibs/log/log.cpp -std=c++11 -lstdc++ -lm -lboost_system -lboost_iostreams -lpthread + * clang -O2 -o mini_scanmon mini_scanmon.cpp dialog.cpp ../../tlibs/net/tcp.cpp ../../tlibs/log/log.cpp -std=c++11 -lstdc++ -lboost_system -lm -lpthread -ldialog + */ + +#include +#include +#include + +#include "../../tlibs/net/tcp.h" +#include "../../tlibs/log/log.h" +#include "../../tlibs/string/string.h" +#include "dialog.h" + + +using namespace tl; +typedef float t_real; + +static t_real dCtr = 0.; +static t_real dMon = 0.; // or time +static t_real dSel = 0.; +static bool bCountToMon = 1; + + +static const std::string strCtr = "nicos/ctr1/value"; +static const std::string strTim = "nicos/timer/value"; +static const std::string strSel = "nicos/timer/preselection"; + + +void refresh() +{ + t_real dProgress = 0.; + t_real dExpCtr = 0.; + + if(!float_equal(dSel, t_real(0.))) + { + dProgress = dMon / dSel; + if(!float_equal(dProgress, t_real(0.))) + dExpCtr = dCtr / dProgress; + } + + if(dProgress < t_real(0.)) dProgress = t_real(0.); + else if(dProgress > t_real(1.)) dProgress = t_real(1.); + + + std::ostringstream ostr; + ostr.precision(2); + + /*ostr << "\r" + << "Counts: " << std::fixed << dCtr + << ", Expected: " << std::fixed << dExpCtr + << ", Scan progress: " << std::fixed << dProgress*100. << " % (" + << std::fixed << dMon << " of " << dSel << " monitor counts)." + << " "; + + std::cout << ostr.str(); + std::cout.flush();*/ + + std::string strMon = "Monitor: "; + if(!bCountToMon) + strMon = "Time: "; + ostr << "Counts: " << std::fixed << dCtr << "\n"; + ostr << "Expected: " << std::fixed << int(std::round(dExpCtr)) << " (" << dExpCtr << ")\n"; + ostr << strMon << std::fixed << dMon << " of " << dSel + << (bCountToMon ? " counts" : " seconds") << "\n"; + ostr << "Progress: " << std::fixed << dProgress*t_real(100.) << " %"; + set_progress(int(std::round(dProgress*t_real(100.))), ostr.str()); +} + + +void disconnected(const std::string& strHost, const std::string& strSrv) +{ + //log_info("Disconnected from ", strHost, " on port ", strSrv, ".");; +} + +void connected(const std::string& strHost, const std::string& strSrv) +{ + //log_info("Connected to ", strHost, " on port ", strSrv, "."); +} + +void received_sics(const std::string& strMsg) +{ + //log_info("Received: ", strMsg); + + std::pair pair = split_first(strMsg, "=", true); + + if(str_is_equal(pair.first, "counter.Monitor 1")) + dMon = str_to_var(pair.second); + else if(str_is_equal(pair.first, "counter.Counts")) + dCtr = str_to_var(pair.second); + else if(str_is_equal(pair.first, "counter.Preset")) + dSel = str_to_var(pair.second); + + refresh(); +} + +void received_nicos(const std::string& strMsg) +{ + //log_info("Received: ", strMsg); + + std::pair pair = split_first(strMsg, "=", true); + + if(pair.first == strTim) + dMon = str_to_var(pair.second); + else if(pair.first == strCtr) + dCtr = str_to_var(pair.second); + else if(pair.first == strSel) + dSel = str_to_var(pair.second); + + refresh(); +} + + + +int main(int argc, char** argv) +{ + bool bUseNicos = 1; + + if(argc == 3) + { + bUseNicos = 1; + bCountToMon = 0; + } + else if(argc == 5) + { + bUseNicos = 0; + bCountToMon = 1; + } + else + { + std::cerr << "Usage: \n" + << "\t" << argv[0] << " \n" + << "\t" << argv[0] << " \n\n" + << "\t e.g.: " << argv[0] << " mira1.mira.frm2 14869" + << std::endl; + return -1; + } + + + if(!open_progress("Scan Progress")) + { + log_err("Cannot open progress dialog."); + return -1; + } + + + TcpTxtClient<> client; + if(bUseNicos) + client.add_receiver(received_nicos); + else + client.add_receiver(received_sics); + client.add_disconnect(disconnected); + client.add_connect(connected); + + + if(!client.connect(argv[1], argv[2])) + { + log_err("Error: Cannot connect to instrument server."); + return -1; + } + + + if(bUseNicos) // nicos + { + for(const std::string& strKey : {strSel, strTim, strCtr}) + { + client.write(strKey + "?\n"); + client.write(strKey + ":\n"); + } + + client.wait(); + } + else // sics + { + std::string strLogin = argv[3]; + std::string strPwd = argv[4]; + client.write(strLogin + " " + strPwd + "\n"); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + while(1) + { + client.write("counter getcounts\ncounter getmonitor 1\ncounter getpreset\n"); + std::this_thread::sleep_for(std::chrono::milliseconds(750)); + } + } + + close_progress(); + return 0; +} diff --git a/tools/misc/addscans.cpp b/tools/misc/addscans.cpp new file mode 100644 index 0000000..af86556 --- /dev/null +++ b/tools/misc/addscans.cpp @@ -0,0 +1,88 @@ +// gcc -I../.. -I. -DNO_IOSTR -o addscans ../../tlibs/file/loadinstr.cpp ../../tlibs/log/log.cpp addscans.cpp -std=c++11 -lstdc++ -lm -lboost_system -lboost_filesystem +// e.g. ./addscans /home/tweber/Auswertungen/MnSi-Mira-15/data3/11009_00016851.dat /home/tweber/Auswertungen/MnSi-Mira-15/data3/11009_00016867.dat merged.dat + +#include +#include +#include +#include "tlibs/file/loadinstr.h" +#include "tlibs/log/log.h" +#include "libs/globals.h" + +using t_real = t_real_glob; + +int main(int argc, char **argv) +{ + if(argc < 3) + { + tl::log_err("Usage:\n\t", argv[0], " ... "); + return -1; + } + + tl::FileFrm<> dat0; + tl::log_info("Loading file ", argv[1]); + if(!dat0.Load(argv[1])) + { + tl::log_err("Cannot load data file ", argv[1], "."); + return -1; + } + + std::string strCnt = dat0.GetCountVar(); + std::string strMon = "mon2"; //dat0.GetMonVar(); + tl::log_info("Count var: ", strCnt, ", monitor var: ", strMon); + + tl::FileInstrBase<>::t_vecVals& vecCnt0 = dat0.GetCol(strCnt); + tl::FileInstrBase<>::t_vecVals& vecMon0 = dat0.GetCol(strMon); + + + for(int iArg=2; iArg dat; + tl::log_info("Loading file ", pcFile); + if(!dat.Load(pcFile)) + { + tl::log_err("Cannot load data file ", pcFile, "."); + return -1; + } + + const tl::FileInstrBase<>::t_vecVals& vecCnt = dat.GetCol(strCnt); + const tl::FileInstrBase<>::t_vecVals& vecMon = dat.GetCol(strMon); + + if(vecCnt.size() != vecCnt0.size() || vecMon.size() != vecMon0.size()) + { + tl::log_err("Size mismatch in file ", pcFile, "."); + return -1; + } + + for(unsigned int i=0; i::t_vecColNames& vecColNames = dat0.GetColNames(); + for(unsigned int i=0; i::t_vecVals& vecCol = dat0.GetCol(strColName); + ofstr << std::setw(20) << vecCol[i]; + } + ofstr << "\n"; + } + + return 0; +} diff --git a/tools/misc/fcc_hk0.cpp b/tools/misc/fcc_hk0.cpp new file mode 100644 index 0000000..3ae53e9 --- /dev/null +++ b/tools/misc/fcc_hk0.cpp @@ -0,0 +1,72 @@ +/* + * gcc -o fcc_hk0 fcc_hk0.cpp -std=c++11 -lstdc++ -lm + * draws 1st BZ of fcc in hk0 plane + * @author: tweber + */ + +#include + +#include +#include +#include +namespace geo = boost::geometry; +namespace trafo = geo::strategy::transform; + +using t_point = geo::model::point; +using t_poly = geo::model::polygon; + +int main() +{ + t_poly bz; + bz.outer().push_back(t_point(-1,-1)); + bz.outer().push_back(t_point(-1,1)); + bz.outer().push_back(t_point(1,1)); + bz.outer().push_back(t_point(1,-1)); + bz.outer().push_back(t_point(-1,-1)); + + t_poly bz_trans, bz1, bz2, bz3, bz4; + geo::transform(bz, bz_trans, trafo::translate_transformer(1. + 0.75*std::sqrt(2.), 0.)); + geo::transform(bz_trans, bz1, trafo::rotate_transformer(45.)); + geo::transform(bz_trans, bz2, trafo::rotate_transformer(-45.)); + geo::transform(bz_trans, bz3, trafo::rotate_transformer(135.)); + geo::transform(bz_trans, bz4, trafo::rotate_transformer(-135.)); + + std::vector vecDiff1, vecDiff2, vecDiff3, vecDiff4; + geo::difference(bz,bz1, vecDiff1); + geo::difference(vecDiff1[0],bz2, vecDiff2); + geo::difference(vecDiff2[0],bz3, vecDiff3); + geo::difference(vecDiff3[0],bz4, vecDiff4); + + geo::svg_mapper svg(std::cout, 1000, 1000); + +/* svg.add(bz); svg.map(bz, "stroke:rgb(0,0,0); fill:rgb(0,0,255)"); + svg.add(bz1); svg.map(bz1, "stroke:rgb(0,0,0); fill:rgb(0,255,0)"); + svg.add(bz2); svg.map(bz2, "stroke:rgb(0,0,0); fill:rgb(0,255,0)"); + svg.add(bz3); svg.map(bz3, "stroke:rgb(0,0,0); fill:rgb(0,255,0)"); + svg.add(bz4); svg.map(bz4, "stroke:rgb(0,0,0); fill:rgb(0,255,0)");*/ + + for(const t_poly& poly : vecDiff4) + { + //geo::transform(poly, poly, trafo::scale_transformer(1e-5, 1e-5)); + svg.add(poly); + svg.map(poly, "stroke:rgb(0,0,0); fill:rgb(0,0,255)"); + } + + + + std::vector vecPts = + { + t_point(0, 0), // Gamma + t_point(0.75, 0.75), // K + t_point(0.75, -0.75), // K + t_point(-0.75, 0.75), // K + t_point(-0.75, -0.75), // K + }; + + for(const t_point& pt : vecPts) + { + svg.add(pt); + svg.map(pt, "stroke:rgb(0,0,0); fill:rgb(0,0,0)", 10); + } + return 0; +} diff --git a/tools/misc/hopfgen.cpp b/tools/misc/hopfgen.cpp new file mode 100644 index 0000000..7c10225 --- /dev/null +++ b/tools/misc/hopfgen.cpp @@ -0,0 +1,92 @@ +// gcc -o hopfgen hopfgen.cpp -std=c++11 -lstdc++ -lm +// @author: tw + +#include "../../tlibs/math/linalg.h" +#include + +namespace ublas = boost::numeric::ublas; + +int main() +{ + unsigned iMaxOrder = 3; + double dStartAngle = 30.; + double dIncAngle = 60.; + double dScale = 0.028; + + double dStartInt = 0.05; + double dIntScale = 0.01; + + double dSigQ = 0.002; + double dSigE = 0.01; + + //ublas::vector vecN = tl::make_vec({1., 0., 0.}); + //ublas::vector vecY = tl::make_vec({0.,-1.,0.}); + ublas::vector vecN = tl::make_vec({1., 1.,0.}); + ublas::vector vecY = tl::make_vec({1.,-1.,0.}); + ublas::vector vecX = vecN; + + vecX /= ublas::norm_2(vecX); + vecY /= ublas::norm_2(vecY); + + + std::cout << "# long. dir.: " << vecX << "\n"; + std::cout << "# trans. dir.: " << vecY << "\n"; + std::cout << "# nuc + long. dir. * scale: " << vecN + vecX*dScale << "\n"; + std::cout << "# nuc + trans. dir. * scale: " << vecN + vecY*dScale << "\n"; + std::cout << "# nuc + long. dir. * 2*scale: " << vecN + vecX*2.*dScale << "\n"; + std::cout << "# nuc + trans. dir. * 2*scale: " << vecN + vecY*2.*dScale << "\n"; + std::cout << "# nuc + long. dir. * 3*scale: " << vecN + vecX*3.*dScale << "\n"; + std::cout << "# nuc + trans. dir. * 3*scale: " << vecN + vecY*3.*dScale << "\n"; + std::cout << "\n"; + + std::cout << "# nuclear peak\n"; + std::cout << vecN[0] << " " << vecN[1] << " " << vecN[2] + << " " << dSigQ << " " << dSigE << " 1\n\n"; + + for(unsigned iOrder=0; iOrder vecLast; + bool bHasLast = 0; + for(double dAngle=dStartAngle; dAngle<=dStartAngle+360.; dAngle+=dIncAngle) + { + ublas::vector vec = + std::cos(dAngle/180.*M_PI)*vecY + + std::sin(dAngle/180.*M_PI)*vecX; + + vec *= dScale*double(iOrder+1); + ublas::vector vecCur = vec; + + vec += vecN; + double dIntensity = dStartInt * std::pow(dIntScale, iOrder); + + if(dAngle < dStartAngle + 360.) + { + std::cout << vec[0] << " " << vec[1] << " " << vec[2] + << " " << dSigQ << " " << dSigE << " " << dIntensity + /*<< " "<< ublas::norm_2(vecCur)*/ << "\n"; + } + + if(bHasLast) + for(unsigned iOrd=0; iOrd vecBetween = + vecLast + double(iOrd+1)*(vecCur - vecLast)/double(iOrder+1); + vecBetween += vecN; + + std::cout << vecBetween[0] << " " << vecBetween[1] << " " << vecBetween[2] + << " " << dSigQ << " " << dSigE << " " << dIntensity + /*<< " " << ublas::norm_2(vecBetween-vecN)*/ << "\n"; + } + + vecLast = vecCur; + bHasLast = 1; + } + + std::cout << "\n"; + } + + std::cout.flush(); + return 0; +} diff --git a/tools/misc/tst_client.cpp b/tools/misc/tst_client.cpp new file mode 100644 index 0000000..4e05424 --- /dev/null +++ b/tools/misc/tst_client.cpp @@ -0,0 +1,77 @@ +/* + * clang -o tst_client -I../.. tst_client.cpp ../../tlibs/net/tcp.cpp ../../tlibs/log/log.cpp -lstdc++ -std=c++11 -lboost_system -lpthread -lm + * @author tw + */ + +#include +#include "../../tlibs/net/tcp.h" +#include "../../tlibs/log/log.h" + +using namespace tl; + +struct TstOut +{ + std::ofstream ofstr; + + TstOut() : ofstr("tst_out.txt") + {} + + void print(const std::string& str) + { + //ofstr << str << std::endl; + std::cout << "out: " << str << std::endl; + } +}; + +static void disconnected(const std::string& strHost, const std::string& strSrv) +{ + log_info("Disconnected from ", strHost, " on port ", strSrv, "."); +} + +static void connected(const std::string& strHost, const std::string& strSrv) +{ + log_info("Connected to ", strHost, " on port ", strSrv, "."); +} + +static void received(const std::string& strMsg) +{ + log_info("Received: ", strMsg, "."); +} + + +int main(int argc, char** argv) +{ + if(argc < 3) + { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + + TcpTxtClient<> client; + //TstOut tstout; + //client.add_receiver(boost::bind(&TstOut::print, &tstout, _1)); + client.add_receiver(received); + client.add_disconnect(disconnected); + client.add_connect(connected); + + + if(!client.connect(argv[1], argv[2])) + { + log_err("Cannot connect."); + return -1; + } + + std::string strMsg; + while(client.is_connected()) + { + std::getline(std::cin, strMsg); + if(strMsg == "!exit!") + break; + + strMsg+="\n"; + client.write(strMsg); + } + + return 0; +} diff --git a/tools/misc/tst_server.cpp b/tools/misc/tst_server.cpp new file mode 100644 index 0000000..e0a7c6e --- /dev/null +++ b/tools/misc/tst_server.cpp @@ -0,0 +1,73 @@ +/** + * test instrument server + * @author tweber + * @date apr-2016 + * clang -o tst_server -I. -I../.. ../../tools/misc/tst_server.cpp ../../tlibs/net/tcp.cpp ../../tlibs/log/log.cpp -lstdc++ -std=c++11 -lboost_system -lboost_iostreams -lpthread -lm + */ + +#include "tlibs/net/tcp.h" +#include "tlibs/log/log.h" +#include "tlibs/string/string.h" +#include "tlibs/file/prop.h" + + +using namespace tl; + +static void disconnected(const std::string& strHost, const std::string& strSrv) +{ + log_info("Disconnected."); +} + +static void connected(unsigned short iPort) +{ + log_info("Listening on port ", iPort, "."); +} + + +int main(int argc, char** argv) +{ + if(argc < 2) + { + log_err("Usage: ", argv[0], " "); + return -1; + } + + + TcpTxtServer<> server; + server.add_disconnect(disconnected); + server.add_server_start(connected); + server.add_receiver([&server](const std::string& strMsg) + { + log_info("Received: ", strMsg); + tl::Prop<> prop; + if(prop.Load("replies.ini")) + { + std::string strKey = strMsg; + std::string strVal = prop.Query("replies/" + strMsg, "0"); + + server.write(strKey + "=" + strVal + "\n"); + } + }); + + + if(!server.start_server(tl::str_to_var(std::string(argv[1])))) + { + log_err("Cannot start server."); + return -1; + } + + log_info("Waiting..."); + server.wait(); + + /*std::string strMsg; + while(server.is_connected()) + { + std::getline(std::cin, strMsg); + if(strMsg == "!exit!") + break; + + strMsg+="\n"; + server.write(strMsg); + }*/ + return 0; +} diff --git a/tools/monteconvo/ConvoDlg.cpp b/tools/monteconvo/ConvoDlg.cpp new file mode 100644 index 0000000..f239a62 --- /dev/null +++ b/tools/monteconvo/ConvoDlg.cpp @@ -0,0 +1,793 @@ +/** + * monte carlo convolution tool + * @author tweber + * @date 2015, 2016 + * @license GPLv2 + */ + +#include "ConvoDlg.h" +#include "tlibs/string/string.h" +#include "tlibs/math/math.h" +#include "tlibs/helper/thread.h" + +#ifndef NO_PY + #include "sqw_py.h" +#endif +#include "TASReso.h" + +#include "libs/globals.h" +#include "libs/globals_qt.h" + +#include +#include +#include +#include + +using t_real = t_real_reso; + + +ConvoDlg::ConvoDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent, Qt::WindowTitleHint|Qt::WindowCloseButtonHint|Qt::WindowMinMaxButtonsHint), + m_pSett(pSett) +{ + setupUi(this); + if(m_pSett) + { + QFont font; + if(m_pSett->contains("main/font_gen") && font.fromString(m_pSett->value("main/font_gen", "").toString())) + setFont(font); + } + + btnStart->setIcon(load_icon("res/media-playback-start.svg")); + btnStop->setIcon(load_icon("res/media-playback-stop.svg")); + btnSaveResult->setIcon(load_icon("res/document-save-as.svg")); + + + m_plotwrap.reset(new QwtPlotWrapper(plot, 3, true)); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::xBottom, ""); + m_plotwrap->GetPlot()->setAxisTitle(QwtPlot::yLeft, "S (a.u.)"); + + + // -------------------------------------------------------------------- + QPen penCurve; + penCurve.setColor(QColor(0,0,0x99)); + penCurve.setWidth(2); + m_plotwrap->GetCurve(0)->setPen(penCurve); + m_plotwrap->GetCurve(0)->setStyle(QwtPlotCurve::CurveStyle::Lines); + m_plotwrap->GetCurve(0)->setTitle("S(Q,w)"); + + QPen penPoints; + penPoints.setColor(QColor(0xff,0,0)); + penPoints.setWidth(4); + m_plotwrap->GetCurve(1)->setPen(penPoints); + m_plotwrap->GetCurve(1)->setStyle(QwtPlotCurve::CurveStyle::Dots); + m_plotwrap->GetCurve(1)->setTitle("S(Q,w)"); + + QPen penScanPoints; + penScanPoints.setColor(QColor(0x00,0x90,0x00)); + penScanPoints.setWidth(6); + m_plotwrap->GetCurve(2)->setPen(penScanPoints); + m_plotwrap->GetCurve(2)->setStyle(QwtPlotCurve::CurveStyle::Dots); + m_plotwrap->GetCurve(2)->setTitle("S(Q,w)"); + // -------------------------------------------------------------------- + + + + // -------------------------------------------------------------------- + // fill sqw combo box + load_sqw_plugins(); + auto vecSqwNames = get_sqw_names(); + for(const auto& tupSqw : vecSqwNames) + { + QString strIdent = std::get<0>(tupSqw).c_str(); + QString strName = std::get<1>(tupSqw).c_str(); + + comboSqw->addItem(strName, strIdent); + } + // -------------------------------------------------------------------- + + + + m_pSqwParamDlg = new SqwParamDlg(this, m_pSett); + QObject::connect(this, SIGNAL(SqwLoaded(const std::vector&)), + m_pSqwParamDlg, SLOT(SqwLoaded(const std::vector&))); + QObject::connect(m_pSqwParamDlg, SIGNAL(SqwParamsChanged(const std::vector&)), + this, SLOT(SqwParamsChanged(const std::vector&))); + + QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(ButtonBoxClicked(QAbstractButton*))); + + QObject::connect(btnBrowseCrys, SIGNAL(clicked()), this, SLOT(browseCrysFiles())); + QObject::connect(btnBrowseRes, SIGNAL(clicked()), this, SLOT(browseResoFiles())); + QObject::connect(btnBrowseSqw, SIGNAL(clicked()), this, SLOT(browseSqwFiles())); + QObject::connect(btnBrowseScan, SIGNAL(clicked()), this, SLOT(browseScanFiles())); + + QObject::connect(btnSqwParams, SIGNAL(clicked()), this, SLOT(showSqwParamDlg())); + QObject::connect(btnSaveResult, SIGNAL(clicked()), this, SLOT(SaveResult())); + + QObject::connect(comboSqw, SIGNAL(currentIndexChanged(int)), this, SLOT(SqwModelChanged(int))); + QObject::connect(editSqw, SIGNAL(textChanged(const QString&)), this, SLOT(createSqwModel(const QString&))); + QObject::connect(editScan, SIGNAL(textChanged(const QString&)), this, SLOT(scanFileChanged(const QString&))); + + QObject::connect(editScale, SIGNAL(textChanged(const QString&)), this, SLOT(scaleChanged())); + QObject::connect(editOffs, SIGNAL(textChanged(const QString&)), this, SLOT(scaleChanged())); + + QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(Start())); + QObject::connect(btnStop, SIGNAL(clicked()), this, SLOT(Stop())); + + LoadSettings(); +} + + +ConvoDlg::~ConvoDlg() +{ + if(m_pth) + { + if(m_pth->joinable()) + m_pth->join(); + delete m_pth; + m_pth = nullptr; + } + + if(m_pSqwParamDlg) + { + delete m_pSqwParamDlg; + m_pSqwParamDlg = nullptr; + } +} + + +void ConvoDlg::SaveResult() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSett && !m_pSett->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSett) + strDirLast = m_pSett->value("convo/last_dir_result", ".").toString(); + + QString strFile = QFileDialog::getSaveFileName(this, + "Save Scan", strDirLast, "Data Files (*.dat *.DAT)", nullptr, fileopt); + + if(strFile == "") + return; + + std::string strFile1 = strFile.toStdString(); + std::string strDir = tl::get_dir(strFile1); + + std::ofstream ofstr(strFile1); + if(!ofstr) + { + QMessageBox::critical(this, "Error", "Could not open file."); + return; + } + + std::string strResult = textResult->toPlainText().toStdString(); + ofstr.write(strResult.c_str(), strResult.size()); + + if(m_pSett) + m_pSett->setValue("convo/last_dir_result", QString(strDir.c_str())); +} + + +void ConvoDlg::SqwModelChanged(int) +{ + editSqw->clear(); + emit SqwLoaded(std::vector{}); +} + +void ConvoDlg::createSqwModel(const QString& qstrFile) +{ + if(m_pSqw) + { + m_pSqw.reset(); + emit SqwLoaded(std::vector{}); + } + + std::string strSqwIdent = comboSqw->itemData(comboSqw->currentIndex()).toString().toStdString(); + std::string strSqwFile = qstrFile.toStdString(); + tl::trim(strSqwFile); + + if(strSqwFile == "") + { + QMessageBox::critical(this, "Error", "No S(q,w) config file given."); + return; + } + +#ifdef NO_PY + if(strSqwIdent == "py") + { + QMessageBox::critical(this, "Error", "Compiled without python support."); + return; + } +#endif + + m_pSqw = construct_sqw(strSqwIdent, strSqwFile); + if(!m_pSqw) + { + QMessageBox::critical(this, "Error", "Unknown S(q,w) model selected."); + return; + } + + if(m_pSqw && m_pSqw->IsOk()) + emit SqwLoaded(m_pSqw->GetVars()); + else + { + QMessageBox::critical(this, "Error", "Could not create S(q,w)."); + return; + } +} + + +void ConvoDlg::SqwParamsChanged(const std::vector& vecVars) +{ + if(!m_pSqw) + return; + m_pSqw->SetVars(vecVars); + +#ifndef NDEBUG + // check: read parameters back in + emit SqwLoaded(m_pSqw->GetVars()); +#endif +} + + +void ConvoDlg::Start() +{ + bool bUseScan = m_bUseScan && checkScan->isChecked(); + t_real dScale = tl::str_to_var(editScale->text().toStdString()); + t_real dOffs = tl::str_to_var(editOffs->text().toStdString()); + + m_atStop.store(false); + + btnStart->setEnabled(false); + tabSettings->setEnabled(false); + btnStop->setEnabled(true); + tabWidget->setCurrentWidget(tabPlot); + + bool bForceDeferred = false; + std::string strSqwIdent = comboSqw->itemData(comboSqw->currentIndex()).toString().toStdString(); + if(strSqwIdent == "py") + bForceDeferred = true; + Qt::ConnectionType connty = bForceDeferred ? Qt::ConnectionType::DirectConnection + : Qt::ConnectionType::BlockingQueuedConnection; + + std::function fkt = [this, connty, bForceDeferred, bUseScan, dScale, dOffs] + { + std::function fktEnableButtons = [this] + { + QMetaObject::invokeMethod(btnStop, "setEnabled", Q_ARG(bool, false)); + QMetaObject::invokeMethod(tabSettings, "setEnabled", Q_ARG(bool, true)); + QMetaObject::invokeMethod(btnStart, "setEnabled", Q_ARG(bool, true)); + }; + + const bool bUseR0 = true; + const unsigned int iNumNeutrons = spinNeutrons->value(); + + const unsigned int iNumSteps = spinStepCnt->value(); + std::vector vecH = tl::linspace( + spinStartH->value(), spinStopH->value(), iNumSteps); + std::vector vecK = tl::linspace( + spinStartK->value(), spinStopK->value(), iNumSteps); + std::vector vecL = tl::linspace( + spinStartL->value(), spinStopL->value(), iNumSteps); + std::vector vecE = tl::linspace( + spinStartE->value(), spinStopE->value(), iNumSteps); + + std::string strScanVar = ""; + std::vector *pVecScanX = nullptr; + if(!tl::float_equal(spinStartH->value(), spinStopH->value(), 0.0001)) + { + pVecScanX = &vecH; + strScanVar = "h (rlu)"; + } + else if(!tl::float_equal(spinStartK->value(), spinStopK->value(), 0.0001)) + { + pVecScanX = &vecK; + strScanVar = "k (rlu)"; + } + else if(!tl::float_equal(spinStartL->value(), spinStopL->value(), 0.0001)) + { + pVecScanX = &vecL; + strScanVar = "l (rlu)"; + } + else if(!tl::float_equal(spinStartE->value(), spinStopE->value(), 0.0001)) + { + pVecScanX = &vecE; + strScanVar = "E (meV)"; + } + else + { + //QMessageBox::critical(this, "Error", "No scan variable found."); + fktEnableButtons(); + return; + } + + //QMetaObject::invokeMethod(plot, "setAxisTitle", + // Q_ARG(int, QwtPlot::xBottom), + // Q_ARG(const QString&, QString(strScanVar.c_str()))); + //plot->setAxisTitle(QwtPlot::xBottom, strScanVar.c_str()); + + + TASReso reso; + if(!reso.LoadRes(editRes->text().toStdString().c_str())) + { + //QMessageBox::critical(this, "Error", "Could not load resolution file."); + fktEnableButtons(); + return; + } + + if(bUseScan) // get crystal definition from scan file + { + ublas::vector vec1 = + tl::make_vec({m_scan.plane.vec1[0], m_scan.plane.vec1[1], m_scan.plane.vec1[2]}); + ublas::vector vec2 = + tl::make_vec({m_scan.plane.vec2[0], m_scan.plane.vec2[1], m_scan.plane.vec2[2]}); + + reso.SetLattice(m_scan.sample.a, m_scan.sample.b, m_scan.sample.c, + m_scan.sample.alpha, m_scan.sample.beta, m_scan.sample.gamma, + vec1, vec2); + } + else // use crystal config file + { + if(!reso.LoadLattice(editCrys->text().toStdString().c_str())) + { + //QMessageBox::critical(this, "Error", "Could not load crystal file."); + fktEnableButtons(); + return; + } + } + + reso.SetAlgo(ResoAlgo(comboAlgo->currentIndex()+1)); + reso.SetKiFix(comboFixedK->currentIndex()==0); + reso.SetKFix(spinKfix->value()); + + const int iFocMono = comboFocMono->currentIndex(); + const int iFocAna = comboFocAna->currentIndex(); + + unsigned ifocMode = unsigned(ResoFocus::FOC_NONE); + if(iFocMono == 1) ifocMode |= unsigned(ResoFocus::FOC_MONO_H); // horizontal + else if(iFocMono == 2) ifocMode |= unsigned(ResoFocus::FOC_MONO_V); // vertical + else if(iFocMono == 3) ifocMode |= unsigned(ResoFocus::FOC_MONO_V)|unsigned(ResoFocus::FOC_MONO_H); // both + if(iFocAna == 1) ifocMode |= unsigned(ResoFocus::FOC_ANA_H); // horizontal + else if(iFocAna == 2) ifocMode |= unsigned(ResoFocus::FOC_ANA_V); // vertical + else if(iFocAna == 3) ifocMode |= unsigned(ResoFocus::FOC_ANA_V)|unsigned(ResoFocus::FOC_ANA_H); // both + + ResoFocus focMode = ResoFocus(ifocMode); + reso.SetOptimalFocus(focMode); + + + if(m_pSqw == nullptr || !m_pSqw->IsOk()) + { + //QMessageBox::critical(this, "Error", "No valid S(q,w) model loaded."); + fktEnableButtons(); + return; + } + + + + std::ostringstream ostrOut; + ostrOut << "#\n"; + ostrOut << "# Format: h k l E S\n"; + ostrOut << "# Neutrons: " << iNumNeutrons << "\n"; + ostrOut << "#\n"; + + QMetaObject::invokeMethod(progress, "setMaximum", Q_ARG(int, iNumSteps)); + QMetaObject::invokeMethod(progress, "setValue", Q_ARG(int, 0)); + + QMetaObject::invokeMethod(textResult, "clear", connty); + + + m_vecQ.clear(); + m_vecS.clear(); + m_vecScaledS.clear(); + + m_vecQ.reserve(iNumSteps); + m_vecS.reserve(iNumSteps); + m_vecScaledS.reserve(iNumSteps); + + unsigned int iNumThreads = bForceDeferred ? 0 : std::thread::hardware_concurrency(); + + tl::ThreadPool()> tp(iNumThreads); + auto& lstFuts = tp.GetFutures(); + + for(unsigned int iStep=0; iStep std::pair + { + if(m_atStop.load()) return std::pair(false, 0.); + + TASReso localreso = reso; + std::vector> vecNeutrons; + + try + { + if(!localreso.SetHKLE(dCurH, dCurK, dCurL, dCurE)) + { + std::ostringstream ostrErr; + ostrErr << "Invalid crystal position: (" << + dCurH << " " << dCurK << " " << dCurL << ") rlu, " + << dCurE << " meV."; + throw tl::Err(ostrErr.str().c_str()); + } + } + catch(const std::exception& ex) + { + //QMessageBox::critical(this, "Error", ex.what()); + tl::log_err(ex.what()); + return std::pair(false, 0.); + } + + Ellipsoid4d elli = + localreso.GenerateMC(iNumNeutrons, vecNeutrons); + + t_real dS = 0.; + t_real dhklE_mean[4] = {0., 0., 0., 0.}; + + for(const ublas::vector& vecHKLE : vecNeutrons) + { + if(m_atStop.load()) return std::pair(false, 0.); + + dS += (*m_pSqw)(vecHKLE[0], vecHKLE[1], vecHKLE[2], vecHKLE[3]); + + for(int i=0; i<4; ++i) + dhklE_mean[i] += vecHKLE[i]; + } + + dS /= t_real(iNumNeutrons); + for(int i=0; i<4; ++i) + dhklE_mean[i] /= t_real(iNumNeutrons); + + if(bUseR0) + dS *= localreso.GetResoResults().dResVol; + if(bUseR0 && localreso.GetResoParams().bCalcR0) + dS *= localreso.GetResoResults().dR0; + + return std::pair(true, dS); + }); + } + + tp.StartTasks(); + + auto iterTask = tp.GetTasks().begin(); + unsigned int iStep = 0; + for(auto &fut : lstFuts) + { + if(m_atStop.load()) break; + + // deferred (in main thread), eval this task manually + if(iNumThreads == 0) + { + (*iterTask)(); + ++iterTask; + } + + std::pair pairS = fut.get(); + if(!pairS.first) + break; + t_real dS = pairS.second; + + ostrOut.precision(16); + ostrOut << std::left << std::setw(20) << vecH[iStep] << " " + << std::left << std::setw(20) << vecK[iStep] << " " + << std::left << std::setw(20) << vecL[iStep] << " " + << std::left << std::setw(20) << vecE[iStep] << " " + << std::left << std::setw(20) << dS << "\n"; + + + m_vecQ.push_back((*pVecScanX)[iStep]); + m_vecS.push_back(dS); + m_vecScaledS.push_back(dS*dScale + dOffs); + + static const std::vector vecNull; + + set_qwt_data()(*m_plotwrap, m_vecQ, m_vecScaledS, 0, false); + set_qwt_data()(*m_plotwrap, m_vecQ, m_vecScaledS, 1, false); + if(bUseScan) + set_qwt_data()(*m_plotwrap, m_scan.vecX, m_scan.vecCts, 2, false); + else + set_qwt_data()(*m_plotwrap, vecNull, vecNull, 2, false); + + //set_zoomer_base(m_plotwrap->GetZoomer(), m_vecQ, m_vecScaledS, true); + QMetaObject::invokeMethod(m_plotwrap->GetPlot(), "replot", connty); + + QMetaObject::invokeMethod(textResult, "setPlainText", connty, + Q_ARG(const QString&, QString(ostrOut.str().c_str()))); + + QMetaObject::invokeMethod(progress, "setValue", Q_ARG(int, iStep+1)); + ++iStep; + } + + ostrOut << "# ---------------- EOF ----------------\n"; + + QMetaObject::invokeMethod(textResult, "setPlainText", connty, + Q_ARG(const QString&, QString(ostrOut.str().c_str()))); + + fktEnableButtons(); + }; + + + if(bForceDeferred) + fkt(); + else + { + if(m_pth) { if(m_pth->joinable()) m_pth->join(); delete m_pth; } + m_pth = new std::thread(std::move(fkt)); + } +} + + +void ConvoDlg::Stop() +{ + m_atStop.store(true); +} + + +void ConvoDlg::scanFileChanged(const QString& qstrFile) +{ + m_bUseScan = 0; + std::string strFile = qstrFile.toStdString(); + tl::trim(strFile); + if(strFile == "") return; + + std::vector vecFiles{strFile}; + + Filter filter; + m_scan = Scan(); + if(!::load_file(vecFiles, m_scan, 1, filter)) + { + tl::log_err("Cannot load scan(s)."); + return; + } + + if(!m_scan.vecPoints.size()) + { + tl::log_err("No points in scan(s)."); + return; + } + + const ScanPoint& ptBegin = *m_scan.vecPoints.cbegin(); + const ScanPoint& ptEnd = *m_scan.vecPoints.crbegin(); + + comboFixedK->setCurrentIndex(m_scan.bKiFixed ? 0 : 1); + spinKfix->setValue(m_scan.dKFix); + + spinStartH->setValue(ptBegin.h); + spinStartK->setValue(ptBegin.k); + spinStartL->setValue(ptBegin.l); + spinStartE->setValue(ptBegin.E / tl::get_one_meV()); + + spinStopH->setValue(ptEnd.h); + spinStopK->setValue(ptEnd.k); + spinStopL->setValue(ptEnd.l); + spinStopE->setValue(ptEnd.E / tl::get_one_meV()); + + m_bUseScan = 1; +} + +void ConvoDlg::scaleChanged() +{ + t_real dScale = tl::str_to_var(editScale->text().toStdString()); + t_real dOffs = tl::str_to_var(editOffs->text().toStdString()); + + m_vecScaledS.resize(m_vecS.size()); + for(std::size_t i=0; i()(*m_plotwrap, m_vecQ, m_vecScaledS, 0, false); + set_qwt_data()(*m_plotwrap, m_vecQ, m_vecScaledS, 1, false); + + m_plotwrap->GetPlot()->replot(); +} + + +// ----------------------------------------------------------------------------- + +void ConvoDlg::browseCrysFiles() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSett && !m_pSett->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSett) + strDirLast = m_pSett->value("convo/last_dir_crys", ".").toString(); + QString strFile = QFileDialog::getOpenFileName(this, + "Open Crystal File...", strDirLast, "Takin files (*.taz *.TAZ)", + nullptr, fileopt); + if(strFile == "") + return; + + editCrys->setText(strFile); + + std::string strDir = tl::get_dir(strFile.toStdString()); + if(m_pSett) + m_pSett->setValue("convo/last_dir_crys", QString(strDir.c_str())); +} + +void ConvoDlg::browseResoFiles() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSett && !m_pSett->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSett) + strDirLast = m_pSett->value("convo/last_dir_reso", ".").toString(); + QString strFile = QFileDialog::getOpenFileName(this, + "Open Resolution File...", strDirLast, "Takin files (*.taz *.TAZ)", + nullptr, fileopt); + if(strFile == "") + return; + + editRes->setText(strFile); + + std::string strDir = tl::get_dir(strFile.toStdString()); + if(m_pSett) + m_pSett->setValue("convo/last_dir_reso", QString(strDir.c_str())); +} + +void ConvoDlg::browseSqwFiles() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSett && !m_pSett->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSett) + strDirLast = m_pSett->value("convo/last_dir_sqw", ".").toString(); + QString strFile = QFileDialog::getOpenFileName(this, + "Open S(q,w) File...", strDirLast, "All S(q,w) files (*.dat *.DAT *.py *.PY)", + nullptr, fileopt); + if(strFile == "") + return; + + editSqw->setText(strFile); + + std::string strDir = tl::get_dir(strFile.toStdString()); + if(m_pSett) + m_pSett->setValue("convo/last_dir_sqw", QString(strDir.c_str())); +} + +void ConvoDlg::browseScanFiles() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSett && !m_pSett->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSett) + strDirLast = m_pSett->value("convo/last_dir_scan", ".").toString(); + QString strFile = QFileDialog::getOpenFileName(this, + "Open S(q,w) File...", strDirLast, "All scan files (*.dat *.DAT *.scn *.SCN)", + nullptr, fileopt); + if(strFile == "") + return; + + editScan->setText(strFile); + + std::string strDir = tl::get_dir(strFile.toStdString()); + if(m_pSett) + m_pSett->setValue("convo/last_dir_scan", QString(strDir.c_str())); +} + +// ----------------------------------------------------------------------------- + + +void ConvoDlg::showSqwParamDlg() +{ + m_pSqwParamDlg->show(); + m_pSqwParamDlg->activateWindow(); +} + +void ConvoDlg::LoadSettings() +{ + if(m_pSett) + { + if(m_pSett->contains("monteconvo/geo")) + restoreGeometry(m_pSett->value("monteconvo/geo").toByteArray()); + + if(m_pSett->contains("monteconvo/algo")) + comboAlgo->setCurrentIndex(m_pSett->value("monteconvo/algo").toInt()); + if(m_pSett->contains("monteconvo/fixedk")) + comboFixedK->setCurrentIndex(m_pSett->value("monteconvo/fixedk").toInt()); + if(m_pSett->contains("monteconvo/mono_foc")) + comboFocMono->setCurrentIndex(m_pSett->value("monteconvo/mono_foc").toInt()); + if(m_pSett->contains("monteconvo/ana_foc")) + comboFocAna->setCurrentIndex(m_pSett->value("monteconvo/ana_foc").toInt()); + if(m_pSett->contains("monteconvo/sqw")) + comboSqw->setCurrentIndex(comboSqw->findData(m_pSett->value("monteconvo/sqw").toString())); + + if(m_pSett->contains("monteconvo/crys")) + editCrys->setText(m_pSett->value("monteconvo/crys").toString()); + if(m_pSett->contains("monteconvo/instr")) + editRes->setText(m_pSett->value("monteconvo/instr").toString()); + if(m_pSett->contains("monteconvo/sqw_conf")) + editSqw->setText(m_pSett->value("monteconvo/sqw_conf").toString()); + if(m_pSett->contains("monteconvo/scanfile")) + editScan->setText(m_pSett->value("monteconvo/scanfile").toString()); + + if(m_pSett->contains("monteconvo/h_from")) + spinStartH->setValue(m_pSett->value("monteconvo/h_from").toDouble()); + if(m_pSett->contains("monteconvo/k_from")) + spinStartK->setValue(m_pSett->value("monteconvo/k_from").toDouble()); + if(m_pSett->contains("monteconvo/l_from")) + spinStartL->setValue(m_pSett->value("monteconvo/l_from").toDouble()); + if(m_pSett->contains("monteconvo/E_from")) + spinStartE->setValue(m_pSett->value("monteconvo/E_from").toDouble()); + if(m_pSett->contains("monteconvo/h_to")) + spinStopH->setValue(m_pSett->value("monteconvo/h_to").toDouble()); + if(m_pSett->contains("monteconvo/k_to")) + spinStopK->setValue(m_pSett->value("monteconvo/k_to").toDouble()); + if(m_pSett->contains("monteconvo/l_to")) + spinStopL->setValue(m_pSett->value("monteconvo/l_to").toDouble()); + if(m_pSett->contains("monteconvo/E_to")) + spinStopE->setValue(m_pSett->value("monteconvo/E_to").toDouble()); + + if(m_pSett->contains("monteconvo/S_scale")) + editScale->setText(m_pSett->value("monteconvo/S_scale").toString()); + if(m_pSett->contains("monteconvo/S_offs")) + editOffs->setText(m_pSett->value("monteconvo/S_offs").toString()); + + if(m_pSett->contains("monteconvo/kfix")) + spinKfix->setValue(m_pSett->value("monteconvo/kfix").toDouble()); + if(m_pSett->contains("monteconvo/neutron_count")) + spinNeutrons->setValue(m_pSett->value("monteconvo/neutron_count").toDouble()); + if(m_pSett->contains("monteconvo/step_count")) + spinStepCnt->setValue(m_pSett->value("monteconvo/step_count").toDouble()); + } +} + +void ConvoDlg::showEvent(QShowEvent *pEvt) +{ + //LoadSettings(); + QDialog::showEvent(pEvt); +} + +void ConvoDlg::ButtonBoxClicked(QAbstractButton *pBtn) +{ + if(pBtn == buttonBox->button(QDialogButtonBox::Close)) + { + if(m_pSett) + { + m_pSett->setValue("monteconvo/geo", saveGeometry()); + + m_pSett->setValue("monteconvo/algo", comboAlgo->currentIndex()); + m_pSett->setValue("monteconvo/fixedk", comboFixedK->currentIndex()); + m_pSett->setValue("monteconvo/mono_foc", comboFocMono->currentIndex()); + m_pSett->setValue("monteconvo/ana_foc", comboFocAna->currentIndex()); + m_pSett->setValue("monteconvo/sqw", comboSqw->itemData(comboSqw->currentIndex()).toString()); + + m_pSett->setValue("monteconvo/crys", editCrys->text()); + m_pSett->setValue("monteconvo/instr", editRes->text()); + m_pSett->setValue("monteconvo/sqw_conf", editSqw->text()); + m_pSett->setValue("monteconvo/scanfile", editScan->text()); + + m_pSett->setValue("monteconvo/h_from", spinStartH->value()); + m_pSett->setValue("monteconvo/k_from", spinStartK->value()); + m_pSett->setValue("monteconvo/l_from", spinStartL->value()); + m_pSett->setValue("monteconvo/E_from", spinStartE->value()); + m_pSett->setValue("monteconvo/h_to", spinStopH->value()); + m_pSett->setValue("monteconvo/k_to", spinStopK->value()); + m_pSett->setValue("monteconvo/l_to", spinStopL->value()); + m_pSett->setValue("monteconvo/E_to", spinStopE->value()); + + m_pSett->setValue("monteconvo/S_scale", editScale->text()); + m_pSett->setValue("monteconvo/S_offs", editOffs->text()); + + m_pSett->setValue("monteconvo/kfix", spinKfix->value()); + m_pSett->setValue("monteconvo/neutron_count", spinNeutrons->value()); + m_pSett->setValue("monteconvo/step_count", spinStepCnt->value()); + } + + QDialog::accept(); + } +} + +#include "ConvoDlg.moc" diff --git a/tools/monteconvo/ConvoDlg.h b/tools/monteconvo/ConvoDlg.h new file mode 100644 index 0000000..7764c01 --- /dev/null +++ b/tools/monteconvo/ConvoDlg.h @@ -0,0 +1,75 @@ +/** + * monte carlo convolution tool + * @author tweber + * @date aug-2015 + * @license GPLv2 + */ + +#ifndef __MCONVO_GUI_H__ +#define __MCONVO_GUI_H__ + +#include +#include +#include +#include +#include + +#include "libs/qthelper.h" +#include "SqwParamDlg.h" +#include "ui/ui_monteconvo.h" +#include "sqwfactory.h" +#include "../res/defs.h" +#include "../convofit/scan.h" + + +class ConvoDlg : public QDialog, Ui::ConvoDlg +{ Q_OBJECT +protected: + std::thread *m_pth = nullptr; + std::atomic m_atStop; + + QSettings *m_pSett = nullptr; + SqwParamDlg *m_pSqwParamDlg = nullptr; + + std::shared_ptr m_pSqw; + std::vector m_vecQ, m_vecS, m_vecScaledS; + std::unique_ptr m_plotwrap; + + bool m_bUseScan = 0; + Scan m_scan; + +protected: + void LoadSettings(); + virtual void showEvent(QShowEvent *pEvt) override; + +protected slots: + void showSqwParamDlg(); + + void browseCrysFiles(); + void browseResoFiles(); + void browseSqwFiles(); + void browseScanFiles(); + + void SqwModelChanged(int); + void createSqwModel(const QString& qstrFile); + void SqwParamsChanged(const std::vector&); + + void scanFileChanged(const QString& qstrFile); + void scaleChanged(); + + void SaveResult(); + + void Start(); + void Stop(); + + void ButtonBoxClicked(QAbstractButton *pBtn); + +public: + ConvoDlg(QWidget* pParent=0, QSettings* pSett=0); + virtual ~ConvoDlg(); + +signals: + void SqwLoaded(const std::vector&); +}; + +#endif diff --git a/tools/monteconvo/SqwParamDlg.cpp b/tools/monteconvo/SqwParamDlg.cpp new file mode 100644 index 0000000..f30a2e7 --- /dev/null +++ b/tools/monteconvo/SqwParamDlg.cpp @@ -0,0 +1,148 @@ +/** + * S(q,w) parameters dialog + * @author tweber + * @date aug-2015 + * @license GPLv2 + */ + +#include "SqwParamDlg.h" +#include + +enum +{ + SQW_NAME = 0, + SQW_TYPE = 1, + SQW_VAL = 2 +}; + +SqwParamDlg::SqwParamDlg(QWidget* pParent, QSettings* pSett) + : QDialog(pParent), m_pSett(pSett) +{ + setupUi(this); + if(m_pSett) + { + QFont font; + if(m_pSett->contains("main/font_gen") && font.fromString(m_pSett->value("main/font_gen", "").toString())) + setFont(font); + } + + tableParams->verticalHeader()->setDefaultSectionSize(tableParams->verticalHeader()->minimumSectionSize()+2); + + connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(ButtonBoxClicked(QAbstractButton*))); + + + if(m_pSett && m_pSett->contains("monteconvo/param_geo")) + restoreGeometry(m_pSett->value("monteconvo/param_geo").toByteArray()); +} + +SqwParamDlg::~SqwParamDlg() +{} + + +void SqwParamDlg::SqwLoaded(const std::vector& vecVars) +{ + const bool bSortTable = tableParams->isSortingEnabled(); + tableParams->setSortingEnabled(0); + + tableParams->setRowCount(vecVars.size()); + tableParams->setColumnWidth(SQW_NAME, 100); + tableParams->setColumnWidth(SQW_TYPE, 75); + tableParams->setColumnWidth(SQW_VAL, 175); + + int iRow=0; + for(const SqwBase::t_var& var : vecVars) + { + const std::string& strName = std::get<0>(var); + const std::string& strType = std::get<1>(var); + const std::string& strVal = std::get<2>(var); + + + QTableWidgetItem *pItemName = tableParams->item(iRow, SQW_NAME); + if(!pItemName) + { + pItemName = new QTableWidgetItem(); + tableParams->setItem(iRow, SQW_NAME, pItemName); + } + pItemName->setFlags((pItemName->flags() & ~Qt::ItemIsEditable) | Qt::ItemIsUserCheckable); + pItemName->setCheckState(Qt::Unchecked); + pItemName->setText(strName.c_str()); + + + QTableWidgetItem *pItemType = tableParams->item(iRow, SQW_TYPE); + if(!pItemType) + { + pItemType = new QTableWidgetItem(); + tableParams->setItem(iRow, SQW_TYPE, pItemType); + } + pItemType->setFlags(pItemType->flags() & ~Qt::ItemIsEditable); + pItemType->setText(strType.c_str()); + + + QTableWidgetItem *pItemVal = tableParams->item(iRow, SQW_VAL); + if(!pItemVal) + { + pItemVal = new QTableWidgetItem(); + tableParams->setItem(iRow, SQW_VAL, pItemVal); + } + pItemVal->setFlags(pItemVal->flags() | Qt::ItemIsEditable); + pItemVal->setText(strVal.c_str()); + + ++iRow; + } + + tableParams->setSortingEnabled(bSortTable); +} + +void SqwParamDlg::SaveSqwParams() +{ + std::vector vecVars; + bool bAnythingSelected=0; + + for(int iRow=0; iRowrowCount(); ++iRow) + { + if(tableParams->item(iRow, SQW_NAME)->checkState() != Qt::Checked) + continue; + + SqwBase::t_var var; + std::get<0>(var) = tableParams->item(iRow, SQW_NAME)->text().toStdString(); + std::get<2>(var) = tableParams->item(iRow, SQW_VAL)->text().toStdString(); + + //std::cerr << std::get<0>(var) << " -> " << std::get<2>(var) << std::endl; + vecVars.push_back(std::move(var)); + bAnythingSelected = 1; + } + + if(bAnythingSelected) + emit SqwParamsChanged(vecVars); + else + QMessageBox::warning(this, "Warning", "No variable is selected for update."); +} + + + +void SqwParamDlg::showEvent(QShowEvent *pEvt) +{ + QDialog::showEvent(pEvt); +} + +void SqwParamDlg::ButtonBoxClicked(QAbstractButton *pBtn) +{ + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ApplyRole || + buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + SaveSqwParams(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::RejectRole) + QDialog::reject(); + + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + if(m_pSett) + m_pSett->setValue("monteconvo/param_geo", saveGeometry()); + + QDialog::accept(); + } +} + + +#include "SqwParamDlg.moc" diff --git a/tools/monteconvo/SqwParamDlg.h b/tools/monteconvo/SqwParamDlg.h new file mode 100644 index 0000000..db34164 --- /dev/null +++ b/tools/monteconvo/SqwParamDlg.h @@ -0,0 +1,41 @@ +/** + * S(q,w) parameters dialog + * @author tweber + * @date aug-2015 + * @license GPLv2 + */ + +#ifndef __SQW_DLG_H__ +#define __SQW_DLG_H__ + +#include +#include + +#include "ui/ui_sqwparams.h" +#include "sqw.h" + + +class SqwParamDlg : public QDialog, Ui::SqwParamDlg +{ Q_OBJECT +protected: + QSettings *m_pSett = nullptr; + +protected: + void SaveSqwParams(); + virtual void showEvent(QShowEvent *pEvt) override; + +public: + SqwParamDlg(QWidget* pParent=nullptr, QSettings* pSett=nullptr); + virtual ~SqwParamDlg(); + +public slots: + void SqwLoaded(const std::vector&); + +protected slots: + void ButtonBoxClicked(QAbstractButton *pBtn); + +signals: + void SqwParamsChanged(const std::vector&); +}; + +#endif diff --git a/tools/monteconvo/TASReso.cpp b/tools/monteconvo/TASReso.cpp new file mode 100644 index 0000000..c871cdb --- /dev/null +++ b/tools/monteconvo/TASReso.cpp @@ -0,0 +1,465 @@ +/* + * loads reso settings + * @author tweber + * @date jul-2015 + * @license GPLv2 + */ + +#include "TASReso.h" +#include "tlibs/math/lattice.h" +#include "tlibs/file/prop.h" +#include "tlibs/log/log.h" +#include "tlibs/helper/thread.h" + +#include + + +typedef t_real_reso t_real; + +using t_vec = ublas::vector; +using t_mat = ublas::matrix; + +static const auto angs = tl::get_one_angstrom(); +static const auto rads = tl::get_one_radian(); +static const auto meV = tl::get_one_meV(); +static const auto cm = tl::get_one_centimeter(); +static const auto meters = tl::get_one_meter(); +static const auto sec = tl::get_one_second(); + +using wavenumber = tl::t_wavenumber_si; + + +TASReso::TASReso() +{ + m_opts.bCenter = 0; + m_opts.coords = McNeutronCoords::RLU; +} + +TASReso::TASReso(const TASReso& res) +{ + operator=(res); +} + +const TASReso& TASReso::operator=(const TASReso& res) +{ + this->m_algo = res.m_algo; + this->m_foc = res.m_foc; + this->m_opts = res.m_opts; + this->m_reso = res.m_reso; + this->m_tofreso = res.m_tofreso; + this->m_res = res.m_res; + this->m_bKiFix = res.m_bKiFix; + this->m_dKFix = res.m_dKFix; + + return *this; +} + + +bool TASReso::LoadLattice(const char* pcXmlFile) +{ + const std::string strXmlRoot("taz/"); + + tl::Prop xml; + if(!xml.Load(pcXmlFile, tl::PropType::XML)) + { + tl::log_err("Cannot load crystal file \"", pcXmlFile, "\"."); + return false; + } + + t_real a = xml.Query((strXmlRoot + "sample/a").c_str(), 0.); + t_real b = xml.Query((strXmlRoot + "sample/b").c_str(), 0.); + t_real c = xml.Query((strXmlRoot + "sample/c").c_str(), 0.); + t_real alpha = tl::d2r(xml.Query((strXmlRoot + "sample/alpha").c_str(), 90.)); + t_real beta = tl::d2r(xml.Query((strXmlRoot + "sample/beta").c_str(), 90.)); + t_real gamma = tl::d2r(xml.Query((strXmlRoot + "sample/gamma").c_str(), 90.)); + + t_real dPlaneX0 = xml.Query((strXmlRoot + "plane/x0").c_str(), 1.); + t_real dPlaneX1 = xml.Query((strXmlRoot + "plane/x1").c_str(), 0.); + t_real dPlaneX2 = xml.Query((strXmlRoot + "plane/x2").c_str(), 0.); + t_real dPlaneY0 = xml.Query((strXmlRoot + "plane/y0").c_str(), 0.); + t_real dPlaneY1 = xml.Query((strXmlRoot + "plane/y1").c_str(), 1.); + t_real dPlaneY2 = xml.Query((strXmlRoot + "plane/y2").c_str(), 0.); + + t_vec vec1 = tl::make_vec({dPlaneX0, dPlaneX1, dPlaneX2}); + t_vec vec2 = tl::make_vec({dPlaneY0, dPlaneY1, dPlaneY2}); + + if(!SetLattice(a, b, c, alpha, beta, gamma, vec1, vec2)) + return false; + + return true; +} + +bool TASReso::LoadRes(const char* pcXmlFile) +{ + const std::string strXmlRoot("taz/"); + + tl::Prop xml; + if(!xml.Load(pcXmlFile, tl::PropType::XML)) + { + tl::log_err("Cannot load resolution file \"", pcXmlFile, "\"."); + return false; + } + + // CN + m_reso.mono_d = xml.Query((strXmlRoot + "reso/mono_d").c_str(), 0.) * angs; + m_reso.mono_mosaic = tl::m2r(xml.Query((strXmlRoot + "reso/mono_mosaic").c_str(), 0.)) * rads; + m_reso.ana_d = xml.Query((strXmlRoot + "reso/ana_d").c_str(), 0.) * angs; + m_reso.ana_mosaic = tl::m2r(xml.Query((strXmlRoot + "reso/ana_mosaic").c_str(), 0.)) * rads; + m_reso.sample_mosaic = tl::m2r(xml.Query((strXmlRoot + "reso/sample_mosaic").c_str(), 0.)) * rads; + + m_reso.coll_h_pre_mono = tl::m2r(xml.Query((strXmlRoot + "reso/h_coll_mono").c_str(), 0.)) * rads; + m_reso.coll_h_pre_sample = tl::m2r(xml.Query((strXmlRoot + "reso/h_coll_before_sample").c_str(), 0.)) * rads; + m_reso.coll_h_post_sample = tl::m2r(xml.Query((strXmlRoot + "reso/h_coll_after_sample").c_str(), 0.)) * rads; + m_reso.coll_h_post_ana = tl::m2r(xml.Query((strXmlRoot + "reso/h_coll_ana").c_str(), 0.)) * rads; + + m_reso.coll_v_pre_mono = tl::m2r(xml.Query((strXmlRoot + "reso/v_coll_mono").c_str(), 0.)) * rads; + m_reso.coll_v_pre_sample = tl::m2r(xml.Query((strXmlRoot + "reso/v_coll_before_sample").c_str(), 0.)) * rads; + m_reso.coll_v_post_sample = tl::m2r(xml.Query((strXmlRoot + "reso/v_coll_after_sample").c_str(), 0.)) * rads; + m_reso.coll_v_post_ana = tl::m2r(xml.Query((strXmlRoot + "reso/v_coll_ana").c_str(), 0.)) * rads; + + m_reso.dmono_refl = xml.Query((strXmlRoot + "reso/mono_refl").c_str(), 0.); + m_reso.dana_effic = xml.Query((strXmlRoot + "reso/ana_effic").c_str(), 0.); + + m_reso.dmono_sense = (xml.Query((strXmlRoot+"reso/mono_scatter_sense").c_str(), 0) ? +1. : -1.); + m_reso.dana_sense = (xml.Query((strXmlRoot+"reso/ana_scatter_sense").c_str(), 0) ? +1. : -1.); + m_reso.dsample_sense = (xml.Query((strXmlRoot+"reso/sample_scatter_sense").c_str(), 1) ? +1. : -1.); + + + // Pop + m_reso.mono_w = xml.Query((strXmlRoot + "reso/pop_mono_w").c_str(), 0.)*cm; + m_reso.mono_h = xml.Query((strXmlRoot + "reso/pop_mono_h").c_str(), 0.)*cm; + m_reso.mono_thick = xml.Query((strXmlRoot + "reso/pop_mono_thick").c_str(), 0.)*cm; + m_reso.mono_curvh = xml.Query((strXmlRoot + "reso/pop_mono_curvh").c_str(), 0.)*cm; + m_reso.mono_curvv = xml.Query((strXmlRoot + "reso/pop_mono_curvv").c_str(), 0.)*cm; + m_reso.bMonoIsCurvedH = (xml.Query((strXmlRoot + "reso/pop_mono_use_curvh").c_str(), 0) != 0); + m_reso.bMonoIsCurvedV = (xml.Query((strXmlRoot + "reso/pop_mono_use_curvv").c_str(), 0) != 0); + m_reso.bMonoIsOptimallyCurvedH = (xml.Query((strXmlRoot + "reso/pop_mono_use_curvh_opt").c_str(), 1) != 0); + m_reso.bMonoIsOptimallyCurvedV = (xml.Query((strXmlRoot + "reso/pop_mono_use_curvv_opt").c_str(), 1) != 0); + + m_reso.ana_w = xml.Query((strXmlRoot + "reso/pop_ana_w").c_str(), 0.)*cm; + m_reso.ana_h = xml.Query((strXmlRoot + "reso/pop_ana_h").c_str(), 0.)*cm; + m_reso.ana_thick = xml.Query((strXmlRoot + "reso/pop_ana_thick").c_str(), 0.)*cm; + m_reso.ana_curvh = xml.Query((strXmlRoot + "reso/pop_ana_curvh").c_str(), 0.)*cm; + m_reso.ana_curvv = xml.Query((strXmlRoot + "reso/pop_ana_curvv").c_str(), 0.)*cm; + m_reso.bAnaIsCurvedH = (xml.Query((strXmlRoot + "reso/pop_ana_use_curvh").c_str(), 0) != 0); + m_reso.bAnaIsCurvedV = (xml.Query((strXmlRoot + "reso/pop_ana_use_curvv").c_str(), 0) != 0); + m_reso.bAnaIsOptimallyCurvedH = (xml.Query((strXmlRoot + "reso/pop_ana_use_curvh_opt").c_str(), 1) != 0); + m_reso.bAnaIsOptimallyCurvedV = (xml.Query((strXmlRoot + "reso/pop_ana_use_curvv_opt").c_str(), 1) != 0); + + m_reso.bSampleCub = (xml.Query((strXmlRoot + "reso/pop_sample_cuboid").c_str(), 0) != 0); + m_reso.sample_w_q = xml.Query((strXmlRoot + "reso/pop_sample_wq").c_str(), 0.)*cm; + m_reso.sample_w_perpq = xml.Query((strXmlRoot + "reso/pop_sampe_wperpq").c_str(), 0.)*cm; + m_reso.sample_h = xml.Query((strXmlRoot + "reso/pop_sample_h").c_str(), 0.)*cm; + + m_reso.bSrcRect = (xml.Query((strXmlRoot + "reso/pop_source_rect").c_str(), 0) != 0); + m_reso.src_w = xml.Query((strXmlRoot + "reso/pop_src_w").c_str(), 0.)*cm; + m_reso.src_h = xml.Query((strXmlRoot + "reso/pop_src_h").c_str(), 0.)*cm; + + m_reso.bDetRect = (xml.Query((strXmlRoot + "reso/pop_det_rect").c_str(), 0) != 0); + m_reso.det_w = xml.Query((strXmlRoot + "reso/pop_det_w").c_str(), 0.)*cm; + m_reso.det_h = xml.Query((strXmlRoot + "reso/pop_det_h").c_str(), 0.)*cm; + + m_reso.bGuide = (xml.Query((strXmlRoot + "reso/use_guide").c_str(), 0) != 0); + m_reso.guide_div_h = tl::m2r(xml.Query((strXmlRoot + "reso/pop_guide_divh").c_str(), 0.)) * rads; + m_reso.guide_div_v = tl::m2r(xml.Query((strXmlRoot + "reso/pop_guide_divv").c_str(), 0.)) * rads; + + m_reso.dist_mono_sample = xml.Query((strXmlRoot + "reso/pop_dist_mono_sample").c_str(), 0.)*cm; + m_reso.dist_sample_ana = xml.Query((strXmlRoot + "reso/pop_dist_sample_ana").c_str(), 0.)*cm; + m_reso.dist_ana_det = xml.Query((strXmlRoot + "reso/pop_dist_ana_det").c_str(), 0.)*cm; + m_reso.dist_src_mono = xml.Query((strXmlRoot + "reso/pop_dist_src_mono").c_str(), 0.)*cm; + + + // Eck + m_reso.mono_mosaic_v = tl::m2r(xml.Query((strXmlRoot + "reso/eck_mono_mosaic_v").c_str(), 0.)) * rads; + m_reso.ana_mosaic_v = tl::m2r(xml.Query((strXmlRoot + "reso/eck_ana_mosaic_v").c_str(), 0.)) * rads; + m_reso.pos_x = xml.Query((strXmlRoot + "reso/eck_sample_pos_x").c_str(), 0.)*cm; + m_reso.pos_y = xml.Query((strXmlRoot + "reso/eck_sample_pos_y").c_str(), 0.)*cm; + m_reso.pos_z = xml.Query((strXmlRoot + "reso/eck_sample_pos_z").c_str(), 0.)*cm; + + // TODO + m_reso.mono_numtiles_h = 1; + m_reso.mono_numtiles_v = 1; + m_reso.ana_numtiles_h = 1; + m_reso.ana_numtiles_v = 1; + + + // TOF + m_tofreso.len_pulse_mono = xml.Query((strXmlRoot + "reso/viol_dist_pulse_mono").c_str(), 0.) * cm; + m_tofreso.len_mono_sample = xml.Query((strXmlRoot + "reso/viol_dist_mono_sample").c_str(), 0.) * cm; + m_tofreso.len_sample_det = xml.Query((strXmlRoot + "reso/viol_dist_sample_det").c_str(), 0.) * cm; + + m_tofreso.sig_len_pulse_mono = xml.Query((strXmlRoot + "reso/viol_dist_pulse_mono_sig").c_str(), 0.) * cm; + m_tofreso.sig_len_mono_sample = xml.Query((strXmlRoot + "reso/viol_dist_mono_sample_sig").c_str(), 0.) * cm; + m_tofreso.sig_len_sample_det = xml.Query((strXmlRoot + "reso/viol_dist_sample_det_sig").c_str(), 0.) * cm; + + m_tofreso.sig_pulse = (xml.Query((strXmlRoot + "reso/viol_time_pulse_sig").c_str(), 0.) * 1e-6) * sec; + m_tofreso.sig_mono = (xml.Query((strXmlRoot + "reso/viol_time_mono_sig").c_str(), 0.) * 1e-6) * sec; + m_tofreso.sig_det = (xml.Query((strXmlRoot + "reso/viol_time_det_sig").c_str(), 0.) * 1e-6) * sec; + + m_tofreso.twotheta_i = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_tt_i").c_str(), 0.)) * rads; + m_tofreso.angle_outplane_i = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_ph_i").c_str(), 0.)) * rads; + m_tofreso.angle_outplane_f = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_ph_f").c_str(), 0.)) * rads; + + m_tofreso.sig_twotheta_i = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_tt_i_sig").c_str(), 0.)) * rads; + m_tofreso.sig_twotheta_f = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_tt_f_sig").c_str(), 0.)) * rads; + m_tofreso.sig_outplane_i = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_ph_i_sig").c_str(), 0.)) * rads; + m_tofreso.sig_outplane_f = tl::d2r(xml.Query((strXmlRoot + "reso/viol_angle_ph_f_sig").c_str(), 0.)) * rads; + + + m_algo = ResoAlgo(xml.Query((strXmlRoot + "reso/algo").c_str(), 0)); + + + // preliminary position + m_tofreso.ki = m_reso.ki = xml.Query((strXmlRoot + "reso/ki").c_str(), 0.) / angs; + m_tofreso.kf = m_reso.kf = xml.Query((strXmlRoot + "reso/kf").c_str(), 0.) / angs; + m_tofreso.E = m_reso.E = xml.Query((strXmlRoot + "reso/E").c_str(), 0.) * meV; + m_tofreso.Q = m_reso.Q = xml.Query((strXmlRoot + "reso/Q").c_str(), 0.) / angs; + + m_dKFix = m_bKiFix ? m_reso.ki*angs : m_reso.kf*angs; + return true; +} + + +bool TASReso::SetLattice(t_real a, t_real b, t_real c, + t_real alpha, t_real beta, t_real gamma, + const t_vec& vec1, const t_vec& vec2) +{ + tl::Lattice latt(a, b, c, alpha, beta, gamma); + + t_mat matB = tl::get_B(latt, 1); + t_mat matU = tl::get_U(vec1, vec2, &matB); + t_mat matUB = ublas::prod(matU, matB); + + t_mat matBinv, matUinv; + bool bHasB = tl::inverse(matB, matBinv); + bool bHasU = tl::inverse(matU, matUinv); + t_mat matUBinv = ublas::prod(matBinv, matUinv); + + bool bHasUB = bHasB && bHasU; + + if(!bHasUB) + { + tl::log_err("Cannot invert UB matrix"); + return false; + } + + + m_opts.matU = matU; + m_opts.matB = matB; + m_opts.matUB = matUB; + m_opts.matUinv = matUinv; + m_opts.matBinv = matBinv; + m_opts.matUBinv = matUBinv; + + ublas::matrix* pMats[] = {&m_opts.matU, &m_opts.matB, &m_opts.matUB, + &m_opts.matUinv, &m_opts.matBinv, &m_opts.matUBinv}; + + for(ublas::matrix *pMat : pMats) + { + pMat->resize(4,4,1); + + for(int i0=0; i0<3; ++i0) + (*pMat)(i0,3) = (*pMat)(3,i0) = 0.; + (*pMat)(3,3) = 1.; + } + + return true; +} + +bool TASReso::SetHKLE(t_real h, t_real k, t_real l, t_real E) +{ + //std::cout << "UB = " << m_opts.matUB << std::endl; + //std::cout << h << " " << k << " " << l << ", " << E << std::endl; + if(m_opts.matUB.size1() < 3 || m_opts.matUB.size2() < 3) + { + const char* pcErr = "Invalid UB matrix."; + tl::log_err(pcErr); + m_res.strErr = pcErr; + m_res.bOk = false; + return false; + } + + t_vec vecHKLE; + if(m_opts.matUB.size1() == 3) + vecHKLE = tl::make_vec({h, k, l}); + else + vecHKLE = tl::make_vec({h, k, l, E}); + + t_vec vecQ = ublas::prod(m_opts.matUB, vecHKLE); + if(vecQ.size() > 3) + vecQ.resize(3, true); + + m_tofreso.Q = m_reso.Q = ublas::norm_2(vecQ) / angs; + m_tofreso.E = m_reso.E = E * meV; + + //tl::log_info("kfix = ", m_dKFix); + wavenumber kother = tl::get_other_k(m_reso.E, m_dKFix/angs, m_bKiFix); + if(m_bKiFix) + { + m_tofreso.ki = m_reso.ki = m_dKFix / angs; + m_tofreso.kf = m_reso.kf = kother; + } + else + { + m_tofreso.ki = m_reso.ki = kother; + m_tofreso.kf = m_reso.kf = m_dKFix / angs; + } + + //tl::log_info("ki = ", m_reso.ki, ", kf = ", m_reso.kf); + //tl::log_info("Q = ", m_reso.Q, ", E = ", m_reso.E/meV, " meV"); + + m_reso.thetam = units::abs(tl::get_mono_twotheta(m_reso.ki, m_reso.mono_d, /*m_reso.dmono_sense>=0.*/1)*t_real(0.5)); + m_reso.thetaa = units::abs(tl::get_mono_twotheta(m_reso.kf, m_reso.ana_d, /*m_reso.dana_sense>=0.*/1)*t_real(0.5)); + m_tofreso.twotheta = m_reso.twotheta = units::abs(tl::get_sample_twotheta(m_reso.ki, m_reso.kf, m_reso.Q, 1)); + + //tl::log_info("thetam = ", tl::r2d(m_reso.thetam/rads)); + //tl::log_info("thetaa = ", tl::r2d(m_reso.thetaa/rads)); + //tl::log_info("twothetas = ", tl::r2d(m_reso.twotheta/rads)); + + m_tofreso.angle_ki_Q = m_reso.angle_ki_Q = tl::get_angle_ki_Q(m_reso.ki, m_reso.kf, m_reso.Q, /*m_reso.dsample_sense>=0.*/1); + m_tofreso.angle_kf_Q = m_reso.angle_kf_Q = tl::get_angle_kf_Q(m_reso.ki, m_reso.kf, m_reso.Q, /*m_reso.dsample_sense>=0.*/1); + + //tl::log_info("kiQ = ", tl::r2d(m_reso.angle_ki_Q/rads)); + //m_reso.angle_ki_Q = units::abs(m_reso.angle_ki_Q); + //m_reso.angle_kf_Q = units::abs(m_reso.angle_kf_Q); + + + if(m_foc == ResoFocus::FOC_NONE) + { + m_reso.bMonoIsCurvedH = m_reso.bMonoIsCurvedV = 0; + m_reso.bAnaIsCurvedH = m_reso.bAnaIsCurvedV = 0; + + //tl::log_info("No focus."); + } + else + { + m_reso.bMonoIsCurvedH = m_reso.bMonoIsOptimallyCurvedH = + (unsigned(m_foc) & unsigned(ResoFocus::FOC_MONO_H)); + m_reso.bMonoIsCurvedV = m_reso.bMonoIsOptimallyCurvedV = + (unsigned(m_foc) & unsigned(ResoFocus::FOC_MONO_V)); + m_reso.bAnaIsCurvedH = m_reso.bAnaIsOptimallyCurvedH = + (unsigned(m_foc) & unsigned(ResoFocus::FOC_ANA_H)); + m_reso.bAnaIsCurvedV = m_reso.bAnaIsOptimallyCurvedV = + (unsigned(m_foc) & unsigned(ResoFocus::FOC_ANA_V)); + + //tl::log_info("Mono focus (h,v): ", m_reso.bMonoIsOptimallyCurvedH, ", ", m_reso.bMonoIsOptimallyCurvedV); + //tl::log_info("Ana focus (h,v): ", m_reso.bAnaIsOptimallyCurvedH, ", ", m_reso.bAnaIsOptimallyCurvedV); + + // remove collimators + /*if(m_reso.bMonoIsCurvedH) + { + m_reso.coll_h_pre_mono = 99999. * rads; + m_reso.coll_h_pre_sample = 99999. * rads; + } + if(m_reso.bMonoIsCurvedV) + { + m_reso.coll_v_pre_mono = 99999. * rads; + m_reso.coll_v_pre_sample = 99999. * rads; + } + if(m_reso.bAnaIsCurvedH) + { + m_reso.coll_h_post_sample = 99999. * rads; + m_reso.coll_h_post_ana = 99999. * rads; + } + if(m_reso.bAnaIsCurvedV) + { + m_reso.coll_v_post_sample = 99999. * rads; + m_reso.coll_v_post_ana = 99999. * rads; + }*/ + } + + + /*tl::log_info("thetam = ", m_reso.thetam); + tl::log_info("thetaa = ", m_reso.thetaa); + tl::log_info("2theta = ", m_reso.twotheta);*/ + + if(std::fabs(vecQ[2]) > tl::get_plane_dist_tolerance()) + { + tl::log_err("Position Q = (", h, " ", k, " ", l, "),", + " E = ", E, " meV not in scattering plane."); + + m_res.strErr = "Not in scattering plane."; + m_res.bOk = false; + return false; + } + + vecQ.resize(2, true); + m_opts.dAngleQVec0 = -tl::vec_angle(vecQ); + //tl::log_info("angle Q vec0 = ", m_opts.dAngleQVec0); + //tl::log_info("calc r0: ", m_reso.bCalcR0); + + // calculate resolution at (hkl) and E + if(m_algo == ResoAlgo::CN) + { + //tl::log_info("Algorithm: Cooper-Nathans (TAS)"); + m_reso.bCalcR0 = false; + m_res = calc_cn(m_reso); + } + else if(m_algo == ResoAlgo::POP) + { + //tl::log_info("Algorithm: Popovici (TAS)"); + //m_reso.bCalcR0 = true; + m_res = calc_pop(m_reso); + } + else if(m_algo == ResoAlgo::ECK) + { + //tl::log_info("Algorithm: Eckold-Sobolev (TAS)"); + m_reso.bCalcR0 = true; + m_res = calc_eck(m_reso); + } + else if(m_algo == ResoAlgo::VIOL) + { + //tl::log_info("Algorithm: Violini (TOF)"); + m_res = calc_viol(m_tofreso); + } + else + { + const char* pcErr = "Unknown algorithm selected."; + tl::log_err(pcErr); + m_res.strErr = pcErr; + m_res.bOk = false; + return false; + } + + if(!m_res.bOk) + { + tl::log_err("Error calculating resolution: ", m_res.strErr); + tl::log_debug("R0: ", m_res.dR0); + tl::log_debug("res: ", m_res.reso); + } + //tl::log_info("Resolution matrix: ", m_res.reso); + return m_res.bOk; +} + +Ellipsoid4d TASReso::GenerateMC(std::size_t iNum, std::vector& vecNeutrons) const +{ + Ellipsoid4d ell4d = calc_res_ellipsoid4d( + m_res.reso, m_res.reso_v, m_res.reso_s, m_res.Q_avg); + if(vecNeutrons.size() != iNum) + vecNeutrons.resize(iNum); + + unsigned int iNumThreads = std::thread::hardware_concurrency(); + std::size_t iNumPerThread = iNum / iNumThreads; + std::size_t iRemaining = iNum % iNumThreads; + + tl::ThreadPool tp(iNumThreads); + for(unsigned iThread=0; iThread::iterator iterBegin = vecNeutrons.begin() + iNumPerThread*iThread; + std::size_t iNumNeutr = iNumPerThread; + if(iThread == iNumThreads-1) + iNumNeutr = iNumPerThread + iRemaining; + + tp.AddTask([iterBegin, iNumNeutr, this, &ell4d]() + { mc_neutrons(ell4d, iNumNeutr, this->m_opts, iterBegin); }); + } + + tp.StartTasks(); + + auto& lstFut = tp.GetFutures(); + for(auto& fut : lstFut) + fut.get(); + + //mc_neutrons(ell4d, iNum, m_opts, vecNeutrons.begin()); + return ell4d; +} diff --git a/tools/monteconvo/TASReso.h b/tools/monteconvo/TASReso.h new file mode 100644 index 0000000..8597b13 --- /dev/null +++ b/tools/monteconvo/TASReso.h @@ -0,0 +1,73 @@ +/* + * loads reso settings + * @author tweber + * @date jul-2015 + * @license GPLv2 + */ + +#ifndef __DO_RESO_H__ +#define __DO_RESO_H__ + +#include "../res/eck.h" +#include "../res/viol.h" +#include "../res/ellipse.h" +#include "../res/mc.h" + + +enum class ResoFocus : unsigned +{ + FOC_NONE = 0, + + FOC_MONO_H = (1<<1), + FOC_MONO_V = (1<<2), + + FOC_ANA_H = (1<<3), + FOC_ANA_V = (1<<4) +}; + + +class TASReso +{ +protected: + ResoAlgo m_algo = ResoAlgo::CN; + ResoFocus m_foc = ResoFocus::FOC_NONE; + + McNeutronOpts> m_opts; + EckParams m_reso; + ViolParams m_tofreso; + ResoResults m_res; + + bool m_bKiFix = 0; + t_real_reso m_dKFix = 1.4; + +public: + TASReso(); + TASReso(const TASReso& res); + const TASReso& operator=(const TASReso& res); + + virtual ~TASReso() = default; + + bool LoadRes(const char* pcXmlFile); + bool LoadLattice(const char* pcXmlFile); + + bool SetLattice(t_real_reso a, t_real_reso b, t_real_reso c, + t_real_reso alpha, t_real_reso beta, t_real_reso gamma, + const ublas::vector& vec1, const ublas::vector& vec2); + bool SetHKLE(t_real_reso h, t_real_reso k, t_real_reso l, t_real_reso E); + Ellipsoid4d GenerateMC(std::size_t iNum, std::vector>&) const; + + void SetKiFix(bool bKiFix) { m_bKiFix = bKiFix; } + void SetKFix(t_real_reso dKFix) { m_dKFix = dKFix; } + + void SetAlgo(ResoAlgo algo) { m_algo = algo; } + void SetOptimalFocus(ResoFocus foc) { m_foc = foc; } + + const EckParams& GetResoParams() const { return m_reso; } + const ViolParams& GetTofResoParams() const { return m_tofreso; } + EckParams& GetResoParams() { return m_reso; } + ViolParams& GetTofResoParams() { return m_tofreso; } + + const ResoResults& GetResoResults() const { return m_res; } +}; + +#endif diff --git a/tools/monteconvo/mconv_main.cpp b/tools/monteconvo/mconv_main.cpp new file mode 100644 index 0000000..89f7713 --- /dev/null +++ b/tools/monteconvo/mconv_main.cpp @@ -0,0 +1,290 @@ +/* + * monte carlo convolution tool + * @author tweber + * @date jun-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include +#include +#include + +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#include "tlibs/file/loaddat.h" +#include "TASReso.h" +#include "sqw.h" +#include "../res/defs.h" + +using t_real = t_real_reso; + + +static inline void usage(const char* pcProg) +{ + std::ostringstream ostr; + ostr << "Usage: " + << "\n\t(1), single point: " << pcProg << " " + << "\n\t(2), phonon model: " << pcProg << " " + << "\n\t(3), S(q,w) file: " << pcProg << " "; + + tl::log_err("Wrong arguments.\n", ostr.str()); +} + + +static inline int monteconvo_simple(const char* pcNeutrons, const char* pcSqw) +{ + std::ifstream ifstrNeutr(pcNeutrons); + if(!ifstrNeutr.is_open()) + { + tl::log_err("Cannot open neutrons file \"", pcNeutrons, "\"."); + return -1; + } + + std::shared_ptr ptrSqw(new SqwKdTree(pcSqw)); + SqwBase *psqw = ptrSqw.get(); + if(!psqw->IsOk()) + { + tl::log_err("Cannot open Sqw file \"", pcSqw, "\"."); + return -2; + } + + unsigned int iCurNeutr = 0; + std::unordered_map mapNeutrParams; + t_real dS = 0.; + t_real dhklE[4] = {0., 0., 0., 0.}; + + while(!ifstrNeutr.eof()) + { + std::string strLine; + std::getline(ifstrNeutr, strLine); + tl::trim(strLine); + + if(strLine.size() == 0) + continue; + + if(strLine[0] == '#') + { + strLine[0] = ' '; + mapNeutrParams.insert(tl::split_first(strLine, std::string(":"), 1)); + continue; + } + + /*if(mapNeutrParams["coord_sys"] != "rlu") + { + tl::log_err("Need rlu coordinate system."); + return -3; + }*/ + + std::vector vecNeutr; + tl::get_tokens(strLine, std::string(" \t"), vecNeutr); + if(vecNeutr.size() != 4) + { + tl::log_err("Need h,k,l,E data."); + return -3; + } + + //tl::log_info("Neutron ", iCurNeutr, ": ", vecNeutr[0], ", ", vecNeutr[1], ", ", vecNeutr[2], ", ", vecNeutr[3]); + + for(int i=0; i<4; ++i) dhklE[i] += vecNeutr[i]; + //sqw.SetNeutronParams(&mapNeutrParams); + dS += (*psqw)(vecNeutr[0], vecNeutr[1], vecNeutr[2], vecNeutr[3]); + + ++iCurNeutr; + } + + dS /= t_real(iCurNeutr+1); + + for(int i=0; i<4; ++i) + dhklE[i] /= t_real(iCurNeutr+1); + + tl::log_info("Processed ", iCurNeutr, " MC neutrons."); + tl::log_info("S(", dhklE[0], ", ", dhklE[1], ", ", dhklE[2], ", ", dhklE[3], ") = ", dS); + return 0; +} + + +static inline int monteconvo(const char* pcRes, const char* pcCrys, + const char* pcSqw, const char* pcSteps, const char* pcOut) +{ + TASReso reso; + tl::log_info("Loading resolution file \"", pcRes, "\"."); + if(!reso.LoadRes(pcRes)) + return -1; + + tl::log_info("Loading crystal file \"", pcRes, "\"."); + if(!reso.LoadLattice(pcCrys)) + return -2; + + + tl::DatFile steps; + tl::log_info("Loading scan steps file \"", pcRes, "\"."); + if(!steps.Load(pcSteps)) + { + tl::log_err("Cannot load steps file."); + return -3; + } + if(steps.GetColumnCount() != 4) + { + tl::log_err("Need 4 columns in step file: h k l E."); + return -3; + } + const unsigned int iNumSteps = steps.GetRowCount(); + tl::log_info("Number of scan steps: ", iNumSteps); + const t_real *pH = steps.GetColumn(0).data(); + const t_real *pK = steps.GetColumn(1).data(); + const t_real *pL = steps.GetColumn(2).data(); + const t_real *pE = steps.GetColumn(3).data(); + + unsigned int iNumNeutrons = 0; + try + { + iNumNeutrons = tl::str_to_var(steps.GetHeader().at("num_neutrons")); + reso.SetAlgo(ResoAlgo(tl::str_to_var(steps.GetHeader().at("algo")))); + bool bFixedKi = tl::str_to_var(steps.GetHeader().at("fixed_ki")); + t_real dKFix = tl::str_to_var(steps.GetHeader().at("kfix")); + + reso.SetKiFix(bFixedKi); + reso.SetKFix(dKFix); + } + catch(const std::out_of_range& ex) + { + tl::log_err("Need keys \"num_neutrons\", \"fixed_ki\", \"kfix\" and \"algo\" in steps file."); + return -3; + } + + + tl::log_info("Number of neutrons: ", iNumNeutrons); + + + std::shared_ptr ptrSqw; + //std::shared_ptr ptrSqw(new SqwElast()); + + if(pcSqw) + { + tl::log_info("Loading S(Q,w) file \"", pcSqw, "\"."); + ptrSqw.reset(new SqwKdTree(pcSqw)); + } + else + { + tl::log_info("Using phonon model."); + ptrSqw.reset(new SqwPhonon(tl::make_vec({4.,4.,0}), + tl::make_vec({0.,0.,1.}), tl::make_vec({1.,-1.,0.}), + 40., M_PI/2., 0.5, 0.5, 1., + 12., M_PI/2., 0.5, 0.5, 1., + 18., M_PI/2., 0.5, 0.5, 1., + 100.)); + } + + + SqwBase *psqw = ptrSqw.get(); + + if(!psqw->IsOk()) + { + tl::log_err("Cannot init Sqw."); + return -4; + } + + + std::ofstream ofstrOut(pcOut); + ofstrOut << "#\n"; + ofstrOut << "# Format: h k l E S\n"; + ofstrOut << "#\n"; + + std::vector> vecNeutrons; + for(unsigned int iStep=0; iStep elli = reso.GenerateMC(iNumNeutrons, vecNeutrons); + + t_real dS = 0.; + t_real dhklE_mean[4] = {0., 0., 0., 0.}; + + std::cout <<"\x1b]0;" + << std::setprecision(3) << dProgress << "%" + << " - calculating S(q,w)" + << "\x07" << std::flush; + for(const ublas::vector& vecHKLE : vecNeutrons) + { + dS += (*psqw)(vecHKLE[0], vecHKLE[1], vecHKLE[2], vecHKLE[3]); + + for(int i=0; i<4; ++i) + dhklE_mean[i] += vecHKLE[i]; + } + + dS /= t_real(iNumNeutrons); + for(int i=0; i<4; ++i) + dhklE_mean[i] /= t_real(iNumNeutrons); + + ofstrOut.precision(16); + ofstrOut << std::left << std::setw(20) << pH[iStep] << " " + << std::left << std::setw(20) << pK[iStep] << " " + << std::left << std::setw(20) << pL[iStep] << " " + << std::left << std::setw(20) << pE[iStep] << " " + << std::left << std::setw(20) << dS << "\n"; + + tl::log_info("Mean position: Q = (", dhklE_mean[0], " ", dhklE_mean[1], " ", dhklE_mean[2], "), E = ", dhklE_mean[3], " meV."); + tl::log_info("S(", pH[iStep], ", ", pK[iStep], ", ", pL[iStep], ", ", pE[iStep], ") = ", dS); + } + std::cout <<"\x1b]0;" << "100%" << "\x07" << std::flush; + + tl::log_info("Wrote output file \"", pcOut, "\"."); + ofstrOut.close(); + return 0; +} + + + +// TODO: create non-Qt xml loader and remove linking to Qt... +#include +#include + +int main(int argc, char** argv) +{ + QApplication app(argc, argv, 0); + std::setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::English); + + if(argc == 3) + { + return monteconvo_simple(argv[1], argv[2]); + } + else if(argc==5) + { + const char *pcRes = argv[1]; + const char *pcCrys = argv[2]; + const char *pcSteps = argv[3]; + const char *pcOut = argv[4]; + return monteconvo(pcRes, pcCrys, 0, pcSteps, pcOut); + } + else if(argc==6) + { + const char *pcRes = argv[1]; + const char *pcCrys = argv[2]; + const char *pcSqw = argv[3]; + const char *pcSteps = argv[4]; + const char *pcOut = argv[5]; + return monteconvo(pcRes, pcCrys, pcSqw, pcSteps, pcOut); + } + else + { + usage(argv[0]); + return -1; + } +} diff --git a/tools/monteconvo/sqw.cpp b/tools/monteconvo/sqw.cpp new file mode 100644 index 0000000..52b0d92 --- /dev/null +++ b/tools/monteconvo/sqw.cpp @@ -0,0 +1,894 @@ +/** + * monte carlo convolution tool + * @author tweber + * @date 2015, 2016 + * @license GPLv2 + */ + +#include "sqw.h" +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#include "tlibs/math/math.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/neutrons.h" +#include +#include + +using t_real = t_real_reso; + + +//------------------------------------------------------------------------------ + + +SqwElast::SqwElast(const char* pcFile) : m_bLoadedFromFile(true) +{ + std::ifstream ifstr(pcFile); + if(!ifstr) + { + m_bLoadedFromFile = false; + tl::log_err("Cannot open config file."); + return; + } + + std::string strLine; + while(std::getline(ifstr, strLine)) + { + tl::trim(strLine); + if(strLine.length()==0 || strLine[0]=='#') + continue; + + std::istringstream istr(strLine); + t_real h=0., k=0. ,l=0., dSigQ=0., dSigE=0., dS=0.; + istr >> h >> k >> l >> dSigQ >> dSigE >> dS; + + AddPeak(h,k,l, dSigQ, dSigE, dS); + } + + tl::log_info("Number of elastic peaks: ", m_lstPeaks.size()); + SqwBase::m_bOk = true; +} + +void SqwElast::AddPeak(t_real h, t_real k, t_real l, t_real dSigQ, t_real dSigE, t_real dS) +{ + ElastPeak pk; + pk.h = h; pk.k = k; pk.l = l; + pk.dSigQ = dSigQ; pk.dSigE = dSigE; + pk.dS = dS; + m_lstPeaks.push_back(std::move(pk)); +} + +t_real SqwElast::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + const ublas::vector vecCur = tl::make_vec({dh, dk, dl}); + + if(!m_bLoadedFromFile) // use nearest integer bragg peak + { + const ublas::vector vecPt = tl::make_vec({std::round(dh), std::round(dk), std::round(dl)}); + + const t_real dDistQ = ublas::norm_2(vecPt-vecCur); + const t_real dSigmaQ = 0.02; + const t_real dSigmaE = 0.02; + + return tl::gauss_model(dDistQ, 0., dSigmaQ, 1., 0.) * + tl::gauss_model(dE, 0., dSigmaE, 1., 0.); + } + else // use bragg peaks from config file + { + t_real dS = 0.; + + for(const ElastPeak& pk : m_lstPeaks) + { + const ublas::vector vecPk = tl::make_vec({pk.h, pk.k, pk.l}); + const t_real dDistQ = ublas::norm_2(vecPk-vecCur); + + dS += pk.dS * tl::gauss_model(dDistQ, 0., pk.dSigQ, 1., 0.) * + tl::gauss_model(dE, 0., pk.dSigE, 1., 0.); + } + + return dS; + } +} + +std::vector SqwElast::GetVars() const +{ + std::vector vecVars; + return vecVars; +} + +void SqwElast::SetVars(const std::vector&) +{ +} + +SqwBase* SqwElast::shallow_copy() const +{ + SqwElast *pElast = new SqwElast(); + *static_cast(pElast) = *static_cast(this); + + pElast->m_bLoadedFromFile = m_bLoadedFromFile; + pElast->m_lstPeaks = m_lstPeaks; // not a shallow copy! + return pElast; +} + +//------------------------------------------------------------------------------ + + +SqwKdTree::SqwKdTree(const char* pcFile) +{ + if(pcFile) + m_bOk = open(pcFile); +} + +bool SqwKdTree::open(const char* pcFile) +{ + m_kd = std::make_shared>(); + + std::ifstream ifstr(pcFile); + if(!ifstr.is_open()) + return false; + + std::list> lstPoints; + std::size_t iCurPoint = 0; + while(!ifstr.eof()) + { + std::string strLine; + std::getline(ifstr, strLine); + tl::trim(strLine); + + if(strLine.length() == 0) + continue; + + if(strLine[0] == '#') + { + strLine[0] = ' '; + m_mapParams.insert(tl::split_first(strLine, std::string(":"), 1)); + continue; + } + + std::vector vecSqw; + tl::get_tokens(strLine, std::string(" \t"), vecSqw); + if(vecSqw.size() != 5) + { + tl::log_err("Need h,k,l,E,S data."); + return false; + } + + lstPoints.push_back(vecSqw); + ++iCurPoint; + } + + tl::log_info("Loaded ", iCurPoint, " S(q,w) points."); + m_kd->Load(lstPoints, 4); + tl::log_info("Generated k-d tree."); + + //std::ofstream ofstrkd("kd.dbg"); + //m_kd->GetRootNode()->print(ofstrkd); + return true; +} + + +t_real SqwKdTree::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + std::vector vechklE = {dh, dk, dl, dE}; + if(!m_kd->IsPointInGrid(vechklE)) + return 0.; + + std::vector vec = m_kd->GetNearestNode(vechklE); + + /*t_real dDist = std::sqrt(std::pow(vec[0]-vechklE[0], 2.) + + std::pow(vec[1]-vechklE[1], 2.) + + std::pow(vec[2]-vechklE[2], 2.) + + std::pow(vec[3]-vechklE[3], 2.)); + tl::log_info("Distance to node: ", dDist);*/ + + //tl::log_info("Nearest node: ", vec[0], ", ", vec[1], ", ", vec[2], ", ", vec[3], ", ", vec[4]); + return vec[4]; +} + +std::vector SqwKdTree::GetVars() const +{ + std::vector vecVars; + + return vecVars; +} + +void SqwKdTree::SetVars(const std::vector&) +{ +} + +SqwBase* SqwKdTree::shallow_copy() const +{ + SqwKdTree *pTree = new SqwKdTree(); + *static_cast(pTree) = *static_cast(this); + + pTree->m_mapParams = m_mapParams; + pTree->m_kd = m_kd; + + return pTree; +} + + +//------------------------------------------------------------------------------ + +template +static std::string vec_to_str(const t_vec& vec) +{ + std::ostringstream ostr; + for(const typename t_vec::value_type& t : vec) + ostr << t << " "; + return ostr.str(); +} + +template +static t_vec str_to_vec(const std::string& str) +{ + typedef typename t_vec::value_type T; + + std::vector vec0; + tl::get_tokens>(str, " \t", vec0); + + t_vec vec(vec0.size()); + for(unsigned int i=0; i>(); +#else + m_kd = std::make_shared>(); +#endif + + const bool bSaveOnlyIndices = 1; + destroy(); + + if(m_vecBragg.size()==0 || m_vecLA.size()==0 || m_vecTA1.size()==0 || m_vecTA2.size()==0) + { + m_bOk = 0; + return; + } + + m_vecLA /= ublas::norm_2(m_vecLA); + m_vecTA1 /= ublas::norm_2(m_vecTA1); + m_vecTA2 /= ublas::norm_2(m_vecTA2); + + tl::log_info("LA: ", m_vecLA); + tl::log_info("TA1: ", m_vecTA1); + tl::log_info("TA2: ", m_vecTA2); + + std::list> lst; + for(t_real dq=-1.; dq<1.; dq+=1./t_real(m_iNumqs)) + { + ublas::vector vecQLA = dq*m_vecLA; + ublas::vector vecQTA1 = dq*m_vecTA1; + ublas::vector vecQTA2 = dq*m_vecTA2; + + vecQLA += m_vecBragg; + vecQTA1 += m_vecBragg; + vecQTA2 += m_vecBragg; + + t_real dELA = disp(dq, m_dLA_amp, m_dLA_freq); + t_real dETA1 = disp(dq, m_dTA1_amp, m_dTA1_freq); + t_real dETA2 = disp(dq, m_dTA2_amp, m_dTA2_freq); + + + t_real dLA_E_HWHM = m_dLA_E_HWHM; + t_real dLA_q_HWHM = m_dLA_q_HWHM; + t_real dTA1_E_HWHM = m_dTA1_E_HWHM; + t_real dTA1_q_HWHM = m_dTA1_q_HWHM; + t_real dTA2_E_HWHM = m_dTA2_E_HWHM; + t_real dTA2_q_HWHM = m_dTA2_q_HWHM; + + t_real dLA_S0 = m_dLA_S0; + t_real dTA1_S0 = m_dTA1_S0; + t_real dTA2_S0 = m_dTA2_S0; + + if(bSaveOnlyIndices) + { + dTA1_E_HWHM = dTA1_q_HWHM = dTA1_S0 = -1.; + dTA2_E_HWHM = dTA2_q_HWHM = dTA2_S0 = -2.; + dLA_E_HWHM = dLA_q_HWHM = dLA_S0 = -3.; + } + + // only generate exact phonon branches, no arcs + if(m_iNumArc==0 || m_iNumArc==1) + { + lst.push_back(std::vector({vecQLA[0], vecQLA[1], vecQLA[2], dELA, dLA_S0, dLA_E_HWHM, dLA_q_HWHM})); + lst.push_back(std::vector({vecQTA1[0], vecQTA1[1], vecQTA1[2], dETA1, dTA1_S0, dTA1_E_HWHM, dTA1_q_HWHM})); + lst.push_back(std::vector({vecQTA2[0], vecQTA2[1], vecQTA2[2], dETA2, dTA2_S0, dTA2_E_HWHM, dTA2_q_HWHM})); + } + else + { + const t_real dArcMax = std::abs(tl::d2r(m_dArcMax)); + for(t_real dph=-dArcMax; dph<=dArcMax; dph+=1./t_real(m_iNumArc)) + { + // ta2 + ublas::vector vecArcTA2TA1 = tl::arc(vecQTA2, vecQTA1, dph); + ublas::vector vecArcTA2LA = tl::arc(vecQTA2, vecQLA, dph); + lst.push_back(std::vector({vecArcTA2TA1[0], vecArcTA2TA1[1], vecArcTA2TA1[2], dETA2, dTA2_S0, dTA2_E_HWHM, dTA2_q_HWHM})); + lst.push_back(std::vector({vecArcTA2LA[0], vecArcTA2LA[1], vecArcTA2LA[2], dETA2, dTA2_S0, dTA2_E_HWHM, dTA2_q_HWHM})); + + // ta1 + ublas::vector vecArcTA1TA2 = tl::arc(vecQTA1, vecQTA2, dph); + ublas::vector vecArcTA1LA = tl::arc(vecQTA1, vecQLA, dph); + lst.push_back(std::vector({vecArcTA1TA2[0], vecArcTA1TA2[1], vecArcTA1TA2[2], dETA1, dTA1_S0, dTA1_E_HWHM, dTA1_q_HWHM})); + lst.push_back(std::vector({vecArcTA1LA[0], vecArcTA1LA[1], vecArcTA1LA[2], dETA1, dTA1_S0, dTA1_E_HWHM, dTA1_q_HWHM})); + + // la + ublas::vector vecArcLATA1 = tl::arc(vecQLA, vecQTA1, dph); + ublas::vector vecArcLATA2 = tl::arc(vecQLA, vecQTA2, dph); + lst.push_back(std::vector({vecArcLATA1[0], vecArcLATA1[1], vecArcLATA1[2], dELA, dLA_S0, dLA_E_HWHM, dLA_q_HWHM})); + lst.push_back(std::vector({vecArcLATA2[0], vecArcLATA2[1], vecArcLATA2[2], dELA, dLA_S0, dLA_E_HWHM, dLA_q_HWHM})); + } + } + } + + tl::log_info("Generated ", lst.size(), " S(q,w) points."); +#ifdef USE_RTREE + m_rt->Load(lst); + tl::log_info("Generated R* tree."); +#else + m_kd->Load(lst, 3); + tl::log_info("Generated k-d tree."); +#endif + + m_bOk = 1; +} + +void SqwPhonon::destroy() +{ +#ifdef USE_RTREE + m_rt->Unload(); +#else + m_kd->Unload(); +#endif +} + +SqwPhonon::SqwPhonon(const ublas::vector& vecBragg, + const ublas::vector& vecTA1, + const ublas::vector& vecTA2, + t_real dLA_amp, t_real dLA_freq, t_real dLA_E_HWHM, t_real dLA_q_HWHM, t_real dLA_S0, + t_real dTA1_amp, t_real dTA1_freq, t_real dTA1_E_HWHM, t_real dTA1_q_HWHM, t_real dTA1_S0, + t_real dTA2_amp, t_real dTA2_freq, t_real dTA2_E_HWHM, t_real dTA2_q_HWHM, t_real dTA2_S0, + t_real dT) + : m_vecBragg(vecBragg), m_vecLA(vecBragg), + m_vecTA1(vecTA1), m_vecTA2(vecTA2), + m_dLA_amp(dLA_amp), m_dLA_freq(dLA_freq), + m_dLA_E_HWHM(dLA_E_HWHM), m_dLA_q_HWHM(dLA_q_HWHM), + m_dLA_S0(dLA_S0), + + m_dTA1_amp(dTA1_amp), m_dTA1_freq(dTA1_freq), + m_dTA1_E_HWHM(dTA1_E_HWHM), m_dTA1_q_HWHM(dTA1_q_HWHM), + m_dTA1_S0(dTA1_S0), + + m_dTA2_amp(dTA2_amp), m_dTA2_freq(dTA2_freq), + m_dTA2_E_HWHM(dTA2_E_HWHM), m_dTA2_q_HWHM(dTA2_q_HWHM), + m_dTA2_S0(dTA2_S0), + + m_dT(dT) +{ + create(); +} + +SqwPhonon::SqwPhonon(const char* pcFile) +{ + std::ifstream ifstr(pcFile); + if(!ifstr) + { + tl::log_err("Cannot open phonon config file \"", pcFile, "\"."); + return; + } + + std::string strLine; + while(std::getline(ifstr, strLine)) + { + std::vector vecToks; + tl::get_tokens(strLine, std::string("=,"), vecToks); + std::for_each(vecToks.begin(), vecToks.end(), [](std::string& str) {tl::trim(str); }); + + if(vecToks.size() == 0) continue; + + //for(const auto& tok : vecToks) std::cout << tok << ", "; + //std::cout << std::endl; + + if(vecToks[0] == "num_qs") m_iNumqs = tl::str_to_var(vecToks[1]); + if(vecToks[0] == "num_arc") m_iNumArc = tl::str_to_var(vecToks[1]); + if(vecToks[0] == "arc_max") m_dArcMax = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "G") m_vecLA = m_vecBragg = tl::make_vec({tl::str_to_var_parse(vecToks[1]), tl::str_to_var_parse(vecToks[2]), tl::str_to_var_parse(vecToks[3])}); + else if(vecToks[0] == "TA1") m_vecTA1 = tl::make_vec({tl::str_to_var_parse(vecToks[1]), tl::str_to_var_parse(vecToks[2]), tl::str_to_var_parse(vecToks[3])}); + else if(vecToks[0] == "TA2") m_vecTA2 = tl::make_vec({tl::str_to_var_parse(vecToks[1]), tl::str_to_var_parse(vecToks[2]), tl::str_to_var_parse(vecToks[3])}); + + else if(vecToks[0] == "LA_amp") m_dLA_amp = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "LA_freq") m_dLA_freq = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "LA_E_HWHM") m_dLA_E_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "LA_q_HWHM") m_dLA_q_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "LA_S0") m_dLA_S0 = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "TA1_amp") m_dTA1_amp = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA1_freq") m_dTA1_freq = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA1_E_HWHM") m_dTA1_E_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA1_q_HWHM") m_dTA1_q_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA1_S0") m_dTA1_S0 = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "TA2_amp") m_dTA2_amp = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA2_freq") m_dTA2_freq = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA2_E_HWHM") m_dTA2_E_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA2_q_HWHM") m_dTA2_q_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "TA2_S0") m_dTA2_S0 = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "inc_amp") m_dIncAmp = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "inc_sig") m_dIncSig = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "T") m_dT = tl::str_to_var_parse(vecToks[1]); + } + + create(); +} + +t_real SqwPhonon::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + std::vector vechklE = {dh, dk, dl, dE}; +#ifdef USE_RTREE + if(!m_rt->IsPointInGrid(vechklE)) return 0.; + std::vector vec = m_rt->GetNearestNode(vechklE); +#else + if(!m_kd->IsPointInGrid(vechklE)) return 0.; + std::vector vec = m_kd->GetNearestNode(vechklE); +#endif + + //std::cout << "query: " << dh << " " << dk << " " << dl << " " << dE << std::endl; + //std::cout << "nearest: " << vec[0] << " " << vec[1] << " " << vec[2] << " " << vec[3] << std::endl; + + t_real dE0 = vec[3]; + t_real dS = vec[4]; + t_real dT = m_dT; + t_real dE_HWHM = vec[5]; + t_real dQ_HWHM = vec[6]; + + // index, not value + if(dE_HWHM < 0.) + { + if(tl::float_equal(dE_HWHM, -1., 0.1)) // TA1 + dE_HWHM = m_dTA1_E_HWHM; + else if(tl::float_equal(dE_HWHM, -2., 0.1)) // TA2 + dE_HWHM = m_dTA2_E_HWHM; + else if(tl::float_equal(dE_HWHM, -3., 0.1)) // LA + dE_HWHM = m_dLA_E_HWHM; + } + if(dQ_HWHM < 0.) + { + if(tl::float_equal(dQ_HWHM, -1., 0.1)) // TA1 + dQ_HWHM = m_dTA1_q_HWHM; + else if(tl::float_equal(dQ_HWHM, -2., 0.1)) // TA2 + dQ_HWHM = m_dTA2_q_HWHM; + else if(tl::float_equal(dQ_HWHM, -3., 0.1)) // LA + dQ_HWHM = m_dLA_q_HWHM; + } + if(dS < 0.) + { + if(tl::float_equal(dS, -1., 0.1)) // TA1 + dS = m_dTA1_S0; + else if(tl::float_equal(dS, -2., 0.1)) // TA2 + dS = m_dTA2_S0; + else if(tl::float_equal(dS, -3., 0.1)) // LA + dS = m_dLA_S0; + } + + t_real dqDist = std::sqrt(std::pow(vec[0]-vechklE[0], 2.) + + std::pow(vec[1]-vechklE[1], 2.) + + std::pow(vec[2]-vechklE[2], 2.)); + + t_real dInc = 0.; + if(!tl::float_equal(m_dIncAmp, 0.)) + dInc = tl::gauss_model(dE, 0., m_dIncSig, m_dIncAmp, 0.); + + return dS * std::abs(tl::DHO_model(dE, dT, dE0, dE_HWHM, 1., 0.)) + * tl::gauss_model(dqDist, 0., dQ_HWHM*tl::HWHM2SIGMA, 1., 0.) + + dInc; +} + +std::vector SqwPhonon::GetVars() const +{ + std::vector vecVars; + + vecVars.push_back(SqwBase::t_var{"num_qs", "uint", tl::var_to_str(m_iNumqs)}); + vecVars.push_back(SqwBase::t_var{"num_arc", "uint", tl::var_to_str(m_iNumArc)}); + vecVars.push_back(SqwBase::t_var{"arc_max", "t_real", tl::var_to_str(m_dArcMax)}); + + vecVars.push_back(SqwBase::t_var{"G", "vector", vec_to_str(m_vecBragg)}); + vecVars.push_back(SqwBase::t_var{"TA1", "vector", vec_to_str(m_vecTA1)}); + vecVars.push_back(SqwBase::t_var{"TA2", "vector", vec_to_str(m_vecTA2)}); + + vecVars.push_back(SqwBase::t_var{"LA_amp", "t_real", tl::var_to_str(m_dLA_amp)}); + vecVars.push_back(SqwBase::t_var{"LA_freq", "t_real", tl::var_to_str(m_dLA_freq)}); + vecVars.push_back(SqwBase::t_var{"LA_E_HWHM", "t_real", tl::var_to_str(m_dLA_E_HWHM)}); + vecVars.push_back(SqwBase::t_var{"LA_q_HWHM", "t_real", tl::var_to_str(m_dLA_q_HWHM)}); + vecVars.push_back(SqwBase::t_var{"LA_S0", "t_real", tl::var_to_str(m_dLA_S0)}); + + vecVars.push_back(SqwBase::t_var{"TA1_amp", "t_real", tl::var_to_str(m_dTA1_amp)}); + vecVars.push_back(SqwBase::t_var{"TA1_freq", "t_real", tl::var_to_str(m_dTA1_freq)}); + vecVars.push_back(SqwBase::t_var{"TA1_E_HWHM", "t_real", tl::var_to_str(m_dTA1_E_HWHM)}); + vecVars.push_back(SqwBase::t_var{"TA1_q_HWHM", "t_real", tl::var_to_str(m_dTA1_q_HWHM)}); + vecVars.push_back(SqwBase::t_var{"TA1_S0", "t_real", tl::var_to_str(m_dTA1_S0)}); + + vecVars.push_back(SqwBase::t_var{"TA2_amp", "t_real", tl::var_to_str(m_dTA2_amp)}); + vecVars.push_back(SqwBase::t_var{"TA2_freq", "t_real", tl::var_to_str(m_dTA2_freq)}); + vecVars.push_back(SqwBase::t_var{"TA2_E_HWHM", "t_real", tl::var_to_str(m_dTA2_E_HWHM)}); + vecVars.push_back(SqwBase::t_var{"TA2_q_HWHM", "t_real", tl::var_to_str(m_dTA2_q_HWHM)}); + vecVars.push_back(SqwBase::t_var{"TA2_S0", "t_real", tl::var_to_str(m_dTA2_S0)}); + + vecVars.push_back(SqwBase::t_var{"inc_amp", "t_real", tl::var_to_str(m_dIncAmp)}); + vecVars.push_back(SqwBase::t_var{"inc_sig", "t_real", tl::var_to_str(m_dIncSig)}); + + vecVars.push_back(SqwBase::t_var{"T", "t_real", tl::var_to_str(m_dT)}); + + return vecVars; +} + +void SqwPhonon::SetVars(const std::vector& vecVars) +{ + if(vecVars.size() == 0) + return; + + for(const SqwBase::t_var& var : vecVars) + { + const std::string& strVar = std::get<0>(var); + const std::string& strVal = std::get<2>(var); + + if(strVar == "num_qs") m_iNumqs = tl::str_to_var(strVal); + if(strVar == "num_arc") m_iNumArc = tl::str_to_var(strVal); + if(strVar == "arc_max") m_dArcMax = tl::str_to_var(strVal); + + else if(strVar == "G") m_vecLA = m_vecBragg = str_to_vec(strVal); + else if(strVar == "TA1") m_vecTA1 = str_to_vec(strVal); + else if(strVar == "TA2") m_vecTA2 = str_to_vec(strVal); + + else if(strVar == "LA_amp") m_dLA_amp = tl::str_to_var(strVal); + else if(strVar == "LA_freq") m_dLA_freq = tl::str_to_var(strVal); + else if(strVar == "LA_E_HWHM") m_dLA_E_HWHM = tl::str_to_var(strVal); + else if(strVar == "LA_q_HWHM") m_dLA_q_HWHM = tl::str_to_var(strVal); + else if(strVar == "LA_S0") m_dLA_S0 = tl::str_to_var(strVal); + + else if(strVar == "TA1_amp") m_dTA1_amp = tl::str_to_var(strVal); + else if(strVar == "TA1_freq") m_dTA1_freq = tl::str_to_var(strVal); + else if(strVar == "TA1_E_HWHM") m_dTA1_E_HWHM = tl::str_to_var(strVal); + else if(strVar == "TA1_q_HWHM") m_dTA1_q_HWHM = tl::str_to_var(strVal); + else if(strVar == "TA1_S0") m_dTA1_S0 = tl::str_to_var(strVal); + + else if(strVar == "TA2_amp") m_dTA2_amp = tl::str_to_var(strVal); + else if(strVar == "TA2_freq") m_dTA2_freq = tl::str_to_var(strVal); + else if(strVar == "TA2_E_HWHM") m_dTA2_E_HWHM = tl::str_to_var(strVal); + else if(strVar == "TA2_q_HWHM") m_dTA2_q_HWHM = tl::str_to_var(strVal); + else if(strVar == "TA2_S0") m_dTA2_S0 = tl::str_to_var(strVal); + + else if(strVar == "inc_amp") m_dIncAmp = tl::str_to_var(strVal); + else if(strVar == "inc_sig") m_dIncSig = tl::str_to_var(strVal); + + else if(strVar == "T") m_dT = tl::str_to_var(strVal); + } + + bool bRecreateTree = 0; + + for(const SqwBase::t_var& var : vecVars) + { + const std::string& strVar = std::get<0>(var); + if(strVar != "T" && strVar.find("HWHM") == std::string::npos && + strVar.find("inc") == std::string::npos && + strVar.find("S0") == std::string::npos) + bRecreateTree = 1; + } + + if(bRecreateTree) + create(); + + //std::cout << "hwhm = " << m_dTA2_E_HWHM << std::endl; + //std::cout << "T = " << m_dT << std::endl; + //std::cout << "amp = " << m_dTA2_amp << std::endl; +} + +SqwBase* SqwPhonon::shallow_copy() const +{ + SqwPhonon *pCpy = new SqwPhonon(); + *static_cast(pCpy) = *static_cast(this); + +#ifdef USE_RTREE + pCpy->m_rt = m_rt; +#else + pCpy->m_kd = m_kd; +#endif + pCpy->m_iNumqs = m_iNumqs; + pCpy->m_iNumArc = m_iNumArc; + pCpy->m_dArcMax = m_dArcMax; + + pCpy->m_vecBragg = m_vecBragg; + pCpy->m_vecLA = m_vecLA; + pCpy->m_vecTA1 = m_vecTA1; + pCpy->m_vecTA2 = m_vecTA2; + + pCpy->m_dLA_amp = m_dLA_amp; + pCpy->m_dLA_freq = m_dLA_freq; + pCpy->m_dLA_E_HWHM = m_dLA_E_HWHM; + pCpy->m_dLA_q_HWHM = m_dLA_q_HWHM; + pCpy->m_dLA_S0 = m_dLA_S0; + + pCpy->m_dTA1_amp = m_dTA1_amp; + pCpy->m_dTA1_freq = m_dTA1_freq; + pCpy->m_dTA1_E_HWHM = m_dTA1_E_HWHM; + pCpy->m_dTA1_q_HWHM = m_dTA1_q_HWHM; + pCpy->m_dTA1_S0 = m_dTA1_S0; + + pCpy->m_dTA2_amp = m_dTA2_amp; + pCpy->m_dTA2_freq = m_dTA2_freq; + pCpy->m_dTA2_E_HWHM = m_dTA2_E_HWHM; + pCpy->m_dTA2_q_HWHM = m_dTA2_q_HWHM; + pCpy->m_dTA2_S0 = m_dTA2_S0; + + pCpy->m_dIncAmp = m_dIncAmp; + pCpy->m_dIncSig = m_dIncSig; + + pCpy->m_dT = m_dT; + return pCpy; +} + + +//------------------------------------------------------------------------------ + + +t_real SqwMagnon::ferro_disp(t_real dq, t_real dD, t_real doffs) +{ + return dq*dq * dD + doffs; +} + +t_real SqwMagnon::antiferro_disp(t_real dq, t_real dD, t_real doffs) +{ + return std::abs(dq)*dD + doffs; +} + +void SqwMagnon::create() +{ +#ifdef USE_RTREE + m_rt = std::make_shared>(); +#else + m_kd = std::make_shared>(); +#endif + + destroy(); + + if(m_vecBragg.size() == 0) + { + m_bOk = 0; + return; + } + + std::list> lst; + + const t_real MAX_Q = 1.; + + for(t_real q=0.; q(), t_real(iPhi)/t_real(m_iNumPoints)); + t_real theta = tl::lerp(0., tl::get_pi(), t_real(iTh)/t_real(m_iNumPoints)); + + t_real qx, qy, qz; + std::tie(qx, qy, qz) = tl::sph_to_cart(q, phi, theta); + qx += m_vecBragg[0]; + qy += m_vecBragg[1]; + qz += m_vecBragg[2]; + + lst.push_back(std::vector({qx, qy, qz, dE, m_dS0, m_dE_HWHM, m_dq_HWHM})); + } + } + } + + tl::log_info("Generated ", lst.size(), " S(q,w) points."); +#ifdef USE_RTREE + m_rt->Load(lst); + tl::log_info("Generated R* tree."); +#else + m_kd->Load(lst, 3); + tl::log_info("Generated k-d tree."); +#endif + + m_bOk = 1; +} + +void SqwMagnon::destroy() +{ +#ifdef USE_RTREE + m_rt->Unload(); +#else + m_kd->Unload(); +#endif +} + +SqwMagnon::SqwMagnon(const char* pcFile) +{ + std::ifstream ifstr(pcFile); + if(!ifstr) + { + tl::log_err("Cannot open magnon config file \"", pcFile, "\"."); + return; + } + + std::string strLine; + while(std::getline(ifstr, strLine)) + { + std::vector vecToks; + tl::get_tokens(strLine, std::string("=,"), vecToks); + std::for_each(vecToks.begin(), vecToks.end(), [](std::string& str) {tl::trim(str); }); + + if(vecToks.size() == 0) continue; + + //for(const auto& tok : vecToks) std::cout << tok << ", "; + //std::cout << std::endl; + + if(vecToks[0] == "num_points") m_iNumPoints = tl::str_to_var(vecToks[1]); + + else if(vecToks[0] == "G") m_vecBragg = tl::make_vec({tl::str_to_var_parse(vecToks[1]), tl::str_to_var_parse(vecToks[2]), tl::str_to_var_parse(vecToks[3])}); + else if(vecToks[0] == "disp") m_iWhichDisp = tl::str_to_var(vecToks[1]); + + else if(vecToks[0] == "D") m_dD = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "offs") m_dOffs = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "E_HWHM") m_dE_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "q_HWHM") m_dq_HWHM = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "S0") m_dS0 = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "inc_amp") m_dIncAmp = tl::str_to_var_parse(vecToks[1]); + else if(vecToks[0] == "inc_sig") m_dIncSig = tl::str_to_var_parse(vecToks[1]); + + else if(vecToks[0] == "T") m_dT = tl::str_to_var_parse(vecToks[1]); + } + + create(); +} + +t_real SqwMagnon::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + std::vector vechklE = {dh, dk, dl, dE}; +#ifdef USE_RTREE + if(!m_rt->IsPointInGrid(vechklE)) return 0.; + std::vector vec = m_rt->GetNearestNode(vechklE); +#else + if(!m_kd->IsPointInGrid(vechklE)) return 0.; + std::vector vec = m_kd->GetNearestNode(vechklE); +#endif + + //std::cout << "query: " << dh << " " << dk << " " << dl << " " << dE << std::endl; + //std::cout << "nearest: " << vec[0] << " " << vec[1] << " " << vec[2] << " " << vec[3] << std::endl; + + t_real dE0 = vec[3]; + t_real dS0 = vec[4]; + t_real dT = m_dT; + t_real dE_HWHM = vec[5]; + t_real dQ_HWHM = vec[6]; + + t_real dqDist = std::sqrt(std::pow(vec[0]-vechklE[0], 2.) + + std::pow(vec[1]-vechklE[1], 2.) + + std::pow(vec[2]-vechklE[2], 2.)); + + t_real dInc = 0.; + if(!tl::float_equal(m_dIncAmp, 0.)) + dInc = tl::gauss_model(dE, 0., m_dIncSig, m_dIncAmp, 0.); + + t_real dS = dS0 * std::abs(tl::DHO_model(dE, dT, dE0, dE_HWHM, 1., 0.)) + * tl::gauss_model(dqDist, 0., dQ_HWHM*tl::HWHM2SIGMA, 1., 0.) + + dInc; + + return dS; +} + +std::vector SqwMagnon::GetVars() const +{ + std::vector vecVars; + + vecVars.push_back(SqwBase::t_var{"num_points", "uint", tl::var_to_str(m_iNumPoints)}); + + vecVars.push_back(SqwBase::t_var{"G", "vector", vec_to_str(m_vecBragg)}); + vecVars.push_back(SqwBase::t_var{"disp", "uint", tl::var_to_str(m_iWhichDisp)}); + + vecVars.push_back(SqwBase::t_var{"D", "t_real", tl::var_to_str(m_dD)}); + vecVars.push_back(SqwBase::t_var{"offs", "t_real", tl::var_to_str(m_dOffs)}); + vecVars.push_back(SqwBase::t_var{"E_HWHM", "t_real", tl::var_to_str(m_dE_HWHM)}); + vecVars.push_back(SqwBase::t_var{"q_HWHM", "t_real", tl::var_to_str(m_dq_HWHM)}); + vecVars.push_back(SqwBase::t_var{"S0", "t_real", tl::var_to_str(m_dS0)}); + + vecVars.push_back(SqwBase::t_var{"inc_amp", "t_real", tl::var_to_str(m_dIncAmp)}); + vecVars.push_back(SqwBase::t_var{"inc_sig", "t_real", tl::var_to_str(m_dIncSig)}); + + vecVars.push_back(SqwBase::t_var{"T", "t_real", tl::var_to_str(m_dT)}); + + return vecVars; +} + +void SqwMagnon::SetVars(const std::vector& vecVars) +{ + if(vecVars.size() == 0) + return; + + for(const SqwBase::t_var& var : vecVars) + { + const std::string& strVar = std::get<0>(var); + const std::string& strVal = std::get<2>(var); + + if(strVar == "num_points") m_iNumPoints = tl::str_to_var(strVal); + + else if(strVar == "G") m_vecBragg = str_to_vec(strVal); + else if(strVar == "disp") m_iWhichDisp = tl::str_to_var(strVal); + + else if(strVar == "D") m_dD = tl::str_to_var(strVal); + else if(strVar == "offs") m_dOffs = tl::str_to_var(strVal); + else if(strVar == "E_HWHM") m_dE_HWHM = tl::str_to_var(strVal); + else if(strVar == "q_HWHM") m_dq_HWHM = tl::str_to_var(strVal); + else if(strVar == "S0") m_dS0 = tl::str_to_var(strVal); + + else if(strVar == "inc_amp") m_dIncAmp = tl::str_to_var(strVal); + else if(strVar == "inc_sig") m_dIncSig = tl::str_to_var(strVal); + + else if(strVar == "T") m_dT = tl::str_to_var(strVal); + } + + bool bRecreateTree = 0; + + for(const SqwBase::t_var& var : vecVars) + { + const std::string& strVar = std::get<0>(var); + if(strVar != "T" && strVar.find("HWHM") == std::string::npos && + strVar.find("inc") == std::string::npos && + strVar.find("S0") == std::string::npos) + bRecreateTree = 1; + } + + if(bRecreateTree) + create(); +} + +SqwBase* SqwMagnon::shallow_copy() const +{ + SqwMagnon *pCpy = new SqwMagnon(); + *static_cast(pCpy) = *static_cast(this); + +#ifdef USE_RTREE + pCpy->m_rt = m_rt; +#else + pCpy->m_kd = m_kd; +#endif + pCpy->m_iNumPoints = m_iNumPoints; + + pCpy->m_vecBragg = m_vecBragg; + pCpy->m_iWhichDisp = m_iWhichDisp; + + pCpy->m_dD = m_dD; + pCpy->m_dOffs = m_dOffs; + pCpy->m_dS0 = m_dS0; + pCpy->m_dE_HWHM = m_dE_HWHM; + pCpy->m_dq_HWHM = m_dq_HWHM; + + pCpy->m_dIncAmp = m_dIncAmp; + pCpy->m_dIncSig = m_dIncSig; + + pCpy->m_dT = m_dT; + + return pCpy; +} diff --git a/tools/monteconvo/sqw.h b/tools/monteconvo/sqw.h new file mode 100644 index 0000000..4da4b9e --- /dev/null +++ b/tools/monteconvo/sqw.h @@ -0,0 +1,210 @@ +/** + * monte carlo convolution tool + * @author tweber + * @date 2015, 2016 + * @license GPLv2 + */ + +#ifndef __MCONV_SQW_H__ +#define __MCONV_SQW_H__ + +//#define USE_RTREE + +#include +#include +#include +#include +#include +#include + +#include "tlibs/math/math.h" +#include "tlibs/math/kd.h" +#include "../res/defs.h" +#include "sqwbase.h" + +#ifdef USE_RTREE + #include "tlibs/math/rt.h" + #define RT_ELEMS 64 +#endif + +namespace ublas = boost::numeric::ublas; + + +// ----------------------------------------------------------------------------- + +struct ElastPeak +{ + t_real_reso h, k, l; + t_real_reso dSigQ, dSigE; + t_real_reso dS; +}; + + +/** + * Bragg peaks + */ +class SqwElast : public SqwBase +{ +protected: + bool m_bLoadedFromFile = false; + std::list m_lstPeaks; + +public: + SqwElast() { SqwBase::m_bOk = true; } + SqwElast(const char* pcFile); + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + void AddPeak(t_real_reso h, t_real_reso k, t_real_reso l, t_real_reso dSigQ, t_real_reso dSigE, t_real_reso dS); + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + + virtual SqwBase* shallow_copy() const override; +}; + + +// ----------------------------------------------------------------------------- + + +/** + * tabulated model + */ +class SqwKdTree : public SqwBase +{ +protected: + std::unordered_map m_mapParams; + std::shared_ptr> m_kd; + +public: + SqwKdTree(const char* pcFile = nullptr); + virtual ~SqwKdTree() = default; + + bool open(const char* pcFile); + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + + virtual SqwBase* shallow_copy() const override; +}; + + +// ----------------------------------------------------------------------------- + + +/** + * simple phonon model + */ +class SqwPhonon : public SqwBase +{ +private: + SqwPhonon() {}; + +protected: + static t_real_reso disp(t_real_reso dq, t_real_reso da, t_real_reso df); + + void create(); + void destroy(); + +protected: +#ifdef USE_RTREE + std::shared_ptr> m_rt; +#else + std::shared_ptr> m_kd; +#endif + unsigned int m_iNumqs = 250; + unsigned int m_iNumArc = 50; + t_real_reso m_dArcMax = 10.; + + ublas::vector m_vecBragg; + + ublas::vector m_vecLA; + ublas::vector m_vecTA1; + ublas::vector m_vecTA2; + + t_real_reso m_dLA_amp=20., m_dLA_freq=M_PI/2., m_dLA_E_HWHM=0.1, m_dLA_q_HWHM=0.1, m_dLA_S0=1.; + t_real_reso m_dTA1_amp=15., m_dTA1_freq=M_PI/2., m_dTA1_E_HWHM=0.1, m_dTA1_q_HWHM=0.1, m_dTA1_S0=1.; + t_real_reso m_dTA2_amp=10., m_dTA2_freq=M_PI/2., m_dTA2_E_HWHM=0.1, m_dTA2_q_HWHM=0.1, m_dTA2_S0=1.; + + t_real_reso m_dIncAmp=0., m_dIncSig=0.1; + t_real_reso m_dT = 100.; + +public: + SqwPhonon(const ublas::vector& vecBragg, + const ublas::vector& vecTA1, + const ublas::vector& vecTA2, + t_real_reso dLA_amp, t_real_reso dLA_freq, t_real_reso dLA_E_HWHM, t_real_reso dLA_q_HWHM, t_real_reso dLA_S0, + t_real_reso dTA1_amp, t_real_reso dTA1_freq, t_real_reso dTA1_E_HWHM, t_real_reso dTA1_q_HWHM, t_real_reso dTA1_S0, + t_real_reso dTA2_amp, t_real_reso dTA2_freq, t_real_reso dTA2_E_HWHM, t_real_reso dTA2_q_HWHM, t_real_reso dTA2_S0, + t_real_reso dT); + SqwPhonon(const char* pcFile); + + virtual ~SqwPhonon() = default; + + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + + const ublas::vector& GetBragg() const { return m_vecBragg; } + const ublas::vector& GetLA() const { return m_vecLA; } + const ublas::vector& GetTA1() const { return m_vecTA1; } + const ublas::vector& GetTA2() const { return m_vecTA2; } + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + + virtual SqwBase* shallow_copy() const override; +}; + + +// ----------------------------------------------------------------------------- + + +/** + * simple magnon model + */ +class SqwMagnon : public SqwBase +{ +private: + SqwMagnon() {}; + +protected: + static t_real_reso ferro_disp(t_real_reso dq, t_real_reso dD, t_real_reso doffs); + static t_real_reso antiferro_disp(t_real_reso dq, t_real_reso dD, t_real_reso doffs); + + void create(); + void destroy(); + +protected: +#ifdef USE_RTREE + std::shared_ptr> m_rt; +#else + std::shared_ptr> m_kd; +#endif + + unsigned short m_iWhichDisp = 0; // 0: ferro, 1: antiferro + unsigned int m_iNumPoints = 100; + + ublas::vector m_vecBragg; + + t_real_reso m_dD = 1., m_dOffs = 0.; + t_real_reso m_dE_HWHM = 0.1, m_dq_HWHM = 0.1; + t_real_reso m_dS0 = 1.; + + t_real_reso m_dIncAmp = 0., m_dIncSig = 0.1; + t_real_reso m_dT = 300.; + +public: + SqwMagnon(const char* pcFile); + virtual ~SqwMagnon() = default; + + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + const ublas::vector& GetBragg() const { return m_vecBragg; } + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + + virtual SqwBase* shallow_copy() const override; +}; + +#endif diff --git a/tools/monteconvo/sqw_py.cpp b/tools/monteconvo/sqw_py.cpp new file mode 100644 index 0000000..622c177 --- /dev/null +++ b/tools/monteconvo/sqw_py.cpp @@ -0,0 +1,184 @@ +/** + * S(Q,w) python interface + * @author tweber + * @date aug-2015 + * @license GPLv2 + */ + +#include "sqw_py.h" +#include "tlibs/string/string.h" + +using t_real = t_real_reso; + + +SqwPy::SqwPy(const char* pcFile) : m_pmtx(std::make_shared()) +{ + std::string strFile = pcFile; + std::string strDir = tl::get_dir(strFile); + std::string strMod = tl::get_file_noext(tl::get_file(strFile)); + + try // mandatory stuff + { + ::Py_Initialize(); + + m_sys = py::import("sys"); + py::dict sysdict = py::extract(m_sys.attr("__dict__")); + py::list path = py::extract(sysdict["path"]); + path.append(strDir.c_str()); + path.append("."); + + m_mod = py::import(strMod.c_str()); + py::dict moddict = py::extract(m_mod.attr("__dict__")); + m_Sqw = moddict["TakinSqw"]; + m_bOk = !!m_Sqw; + + try // optional stuff + { + if(moddict.has_key("TakinInit")) + { + m_Init = moddict["TakinInit"]; + if(!!m_Init) m_Init(); + } + } + catch(const py::error_already_set& ex) {} + } + catch(const py::error_already_set& ex) + { + PyErr_Print(); + PyErr_Clear(); + + m_bOk = 0; + } +} + +SqwPy::~SqwPy() +{ + //::Py_Finalize(); +} + + +t_real SqwPy::operator()(t_real dh, t_real dk, t_real dl, t_real dE) const +{ + if(!m_bOk) return t_real(0); + + std::lock_guard lock(*m_pmtx); + try + { + return py::extract(m_Sqw(dh, dk, dl, dE)); + } + catch(const py::error_already_set& ex) + { + PyErr_Print(); + PyErr_Clear(); + } + + return 0.; +} + + +std::vector SqwPy::GetVars() const +{ + std::vector vecVars; + if(!m_bOk) return vecVars; + + try + { + py::dict dict = py::extract(m_mod.attr("__dict__")); + + for(py::ssize_t i=0; i(dict.items()[i][0]); + if(strName.length() == 0) continue; + if(strName[0] == '_') continue; + + // type + std::string strType = py::extract(dict.items()[i][1] + .attr("__class__").attr("__name__")); + if(strType=="module" || strType=="NoneType" || strType=="type") + continue; + if(strType.find("func") != std::string::npos) + continue; + + // value + std::string strValue = py::extract(dict.items()[i][1] + .attr("__repr__")()); + + SqwBase::t_var var; + std::get<0>(var) = std::move(strName); + std::get<1>(var) = std::move(strType); + std::get<2>(var) = std::move(strValue); + + vecVars.push_back(var); + } + } + catch(const py::error_already_set& ex) + { + PyErr_Print(); + PyErr_Clear(); + } + + return vecVars; +} + + +void SqwPy::SetVars(const std::vector& vecVars) +{ + if(!m_bOk) return; + + try + { + py::dict dict = py::extract(m_mod.attr("__dict__")); + + for(py::ssize_t i=0; i(dict.items()[i][0]); + if(strName.length() == 0) continue; + if(strName[0] == '_') continue; + + // look for the variable name in vecVars + bool bFound = 0; + std::string strNewVal; + for(const SqwBase::t_var& var : vecVars) + { + if(std::get<0>(var) == strName) + { + bFound = 1; + strNewVal = std::get<2>(var); + break; + } + } + if(!bFound) + continue; + + // cast new value to variable type + //auto tyVar = dict.items()[i][1].attr("__class__"); + //dict[strName] = tyVar(strNewVal); + dict[strName] = py::eval(py::str(strNewVal), dict); + } + + // TODO: check for changed parameters and if reinit is needed + if(!!m_Init) m_Init(); + } + catch(const py::error_already_set& ex) + { + PyErr_Print(); + PyErr_Clear(); + } +} + + +SqwBase* SqwPy::shallow_copy() const +{ + SqwPy* pSqw = new SqwPy(); + *static_cast(pSqw) = *static_cast(this); + + pSqw->m_pmtx = this->m_pmtx; + pSqw->m_sys = this->m_sys; + pSqw->m_mod = this->m_mod; + pSqw->m_Sqw = this->m_Sqw; + pSqw->m_Init = this->m_Init; + + return pSqw; +} diff --git a/tools/monteconvo/sqw_py.h b/tools/monteconvo/sqw_py.h new file mode 100644 index 0000000..e8e492a --- /dev/null +++ b/tools/monteconvo/sqw_py.h @@ -0,0 +1,38 @@ +/* + * S(Q,w) python interface + * @author tweber + * @date aug-2015 + * @license GPLv2 + */ + +#ifndef __SQW_PY_H__ +#define __SQW_PY_H__ + +#include "sqw.h" +#include +#include +#include +namespace py = boost::python; + + +class SqwPy : public SqwBase +{ +protected: + mutable std::shared_ptr m_pmtx; + py::object m_sys, m_mod; + py::object m_Sqw, m_Init; + +public: + SqwPy() = default; + SqwPy(const char* pcFile); + virtual ~SqwPy(); + + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const override; + + virtual std::vector GetVars() const override; + virtual void SetVars(const std::vector&) override; + + virtual SqwBase* shallow_copy() const override; +}; + +#endif diff --git a/tools/monteconvo/sqwbase.cpp b/tools/monteconvo/sqwbase.cpp new file mode 100644 index 0000000..e637762 --- /dev/null +++ b/tools/monteconvo/sqwbase.cpp @@ -0,0 +1,27 @@ +/** + * interface for S(q,w) models + * @author tweber + * @date 2015, 2016 + * @license GPLv2 + */ + +#include "sqwbase.h" + + +bool SqwBase::SetVarIfAvail(const std::string& strKey, const std::string& strNewVal) +{ + std::vector vecVars = GetVars(); + for(const t_var& var : vecVars) + { + if(strKey == std::get<0>(var)) + { + t_var varNew = var; + std::get<2>(varNew) = strNewVal; + SetVars(std::vector({varNew})); + + return true; + } + } + + return false; +} diff --git a/tools/monteconvo/sqwbase.h b/tools/monteconvo/sqwbase.h new file mode 100644 index 0000000..37436f8 --- /dev/null +++ b/tools/monteconvo/sqwbase.h @@ -0,0 +1,38 @@ +/** + * interface for S(q,w) models + * @author tweber + * @date 2015, 2016 + * @license GPLv2 + */ + +#ifndef __MCONV_SQW_BASE_H__ +#define __MCONV_SQW_BASE_H__ + +#include +#include +#include +#include "../res/defs.h" + + +class SqwBase +{ +public: + // name, type, value + using t_var = std::tuple; + +protected: + bool m_bOk = false; + +public: + virtual t_real_reso operator()(t_real_reso dh, t_real_reso dk, t_real_reso dl, t_real_reso dE) const = 0; + virtual bool IsOk() const { return m_bOk; } + + virtual std::vector GetVars() const = 0; + virtual void SetVars(const std::vector&) = 0; + virtual bool SetVarIfAvail(const std::string& strKey, const std::string& strNewVal); + + virtual SqwBase* shallow_copy() const = 0; + virtual ~SqwBase() {} +}; + +#endif diff --git a/tools/monteconvo/sqwfactory.cpp b/tools/monteconvo/sqwfactory.cpp new file mode 100644 index 0000000..11a2671 --- /dev/null +++ b/tools/monteconvo/sqwfactory.cpp @@ -0,0 +1,182 @@ +/** + * factory and plugin interface for S(q,w) models + * @author Tobias Weber + * @date 2016 + * @license GPLv2 + */ + +#include "sqwfactory.h" +#include "sqw.h" +#ifndef NO_PY + #include "sqw_py.h" +#endif + +#include "tlibs/log/log.h" +#include "tlibs/file/file.h" +#include "libs/globals.h" +#include "libs/version.h" + +#include +#include +#include + + +// sqw info function: "takin_sqw_info" +// returns: [takin ver, ident, long name] +using t_pfkt_info = std::tuple(*)(); +using t_fkt_info = typename std::remove_pointer::type; + +// sqw module function: "takin_sqw" +using t_pfkt = std::shared_ptr(*)(const std::string&); +using t_fkt = typename std::remove_pointer::type; + +// key: identifier, value: [func, long name] +using t_mapSqw = std::unordered_map>; + +static t_mapSqw g_mapSqw = +{ + { "kd", t_mapSqw::mapped_type { + [](const std::string& strCfgFile) -> std::shared_ptr + { return std::make_shared(strCfgFile.c_str()); }, + "Table" } }, + { "phonon", t_mapSqw::mapped_type { + [](const std::string& strCfgFile) -> std::shared_ptr + { return std::make_shared(strCfgFile.c_str()); }, + "Simple Phonon Model" } }, + { "magnon", t_mapSqw::mapped_type { + [](const std::string& strCfgFile) -> std::shared_ptr + { return std::make_shared(strCfgFile.c_str()); }, + "Simple Magnon Model" } }, +#ifndef NO_PY + { "py", t_mapSqw::mapped_type { + [](const std::string& strCfgFile) -> std::shared_ptr + { return std::make_shared(strCfgFile.c_str()); }, + "Python Model" } }, +#endif + { "elastic", t_mapSqw::mapped_type { + [](const std::string& strCfgFile) -> std::shared_ptr + { return std::make_shared(strCfgFile.c_str()); }, + "Elastic Model" } }, +}; + + + +std::vector> get_sqw_names() +{ + using t_tup = std::tuple; + std::vector vec; + vec.reserve(g_mapSqw.size()); + + for(const t_mapSqw::value_type& val : g_mapSqw) + { + t_tup tup; + std::get<0>(tup) = val.first; + std::get<1>(tup) = std::get<1>(val.second); + + vec.push_back(std::move(tup)); + } + + std::sort(vec.begin(), vec.end(), [](const t_tup& tup0, const t_tup& tup1) -> bool + { + const std::string& str0 = std::get<1>(tup0); + const std::string& str1 = std::get<1>(tup1); + + return std::lexicographical_compare(str0.begin(), str0.end(), str1.begin(), str1.end()); + }); + return vec; +} + +std::shared_ptr construct_sqw(const std::string& strName, + const std::string& strConfigFile) +{ + typename t_mapSqw::const_iterator iter = g_mapSqw.find(strName); + if(iter == g_mapSqw.end()) + { + tl::log_err("No S(q,w) model of name \"", strName, "\" found."); + return nullptr; + } + + //tl::log_debug("Constructing ", iter->first, "."); + return (*std::get<0>(iter->second))(strConfigFile); +} + + +#ifdef USE_PLUGINS + +#include +#include + +void load_sqw_plugins() +{ + namespace so = boost::dll; + // tracking modules for refcounting + static std::vector> g_vecMods; + + static bool bPluginsLoaded = 0; + if(bPluginsLoaded) return; + + std::string strPlugins = find_resource_dir("plugins"); + if(strPlugins != "") + { + tl::log_info("Plugin directory: ", strPlugins); + + std::vector vecPlugins = tl::get_all_files(strPlugins.c_str()); + for(const std::string& strPlugin : vecPlugins) + { + try + { + std::shared_ptr pmod = + std::make_shared(strPlugin); + if(!pmod) continue; + + // import info function + std::function fktInfo = + pmod->get("takin_sqw_info"); + if(!fktInfo) continue; + + auto tupInfo = fktInfo(); + const std::string& strTakVer = std::get<0>(tupInfo); + const std::string& strModIdent = std::get<1>(tupInfo); + const std::string& strModLongName = std::get<2>(tupInfo); + tl::log_debug("Module ident: ", strModIdent); + + if(strTakVer != TAKIN_VER) + { + tl::log_err("Skipping S(q,w) plugin \"", strPlugin, + "\" as it was compiled for Takin version ", strTakVer, + " but this is version ", TAKIN_VER, "."); + continue; + } + + + // import factory function + t_pfkt pFkt = pmod->get("takin_sqw"); + if(!pFkt) continue; + + g_mapSqw.insert( t_mapSqw::value_type { + strModIdent, + t_mapSqw::mapped_type { pFkt, strModLongName } + }); + + + g_vecMods.push_back(pmod); + tl::log_info("Loaded plugin: ", strPlugin); + } + catch(const std::exception& ex) + { + //tl::log_err("Could not load ", strPlugin, ". Reason: ", ex.what()); + } + } + } + + bPluginsLoaded = 1; +} + +#else + +void load_sqw_plugins() +{ + tl::log_err("No S(q,w) plugin interface available."); +} + +#endif diff --git a/tools/monteconvo/sqwfactory.h b/tools/monteconvo/sqwfactory.h new file mode 100644 index 0000000..0c0867e --- /dev/null +++ b/tools/monteconvo/sqwfactory.h @@ -0,0 +1,26 @@ +/** + * factory and plugin interface for S(q,w) models + * @author Tobias Weber + * @date 2016 + * @license GPLv2 + */ + +#ifndef __SQW_FACT_H__ +#define __SQW_FACT_H__ + +#include "sqwbase.h" +#include +#include +#include +#include + + +extern std::shared_ptr construct_sqw(const std::string& strName, + const std::string& strConfigFile); + +// [identifier, long name] +extern std::vector> get_sqw_names(); + + +extern void load_sqw_plugins(); +#endif diff --git a/tools/monteconvo/tst_phonon.cpp b/tools/monteconvo/tst_phonon.cpp new file mode 100644 index 0000000..2625d25 --- /dev/null +++ b/tools/monteconvo/tst_phonon.cpp @@ -0,0 +1,48 @@ +// gcc -o tst_phonon tst_phonon.cpp sqw.cpp ../../tlibs/helper/log.cpp -std=c++11 -I ../.. -lstdc++ -lm + +#include "sqw.h" +#include "tlibs/math/linalg.h" +#include +#include +#include + +typedef ublas::vector t_vec; + +int main() +{ + SqwPhonon ph(tl::make_vec({4.,4.,0}), + tl::make_vec({0.,0.,1.}), + tl::make_vec({1.,-1.,0.}), + 40., M_PI/2., 0.5, 0.5, + 12., M_PI/2., 0.5, 0.5, + 18., M_PI/2., 0.5, 0.5); + + const t_vec& vecBragg = ph.GetBragg(); + const t_vec& vecLA = ph.GetLA(); + const t_vec& vecTA1 = ph.GetTA1(); + const t_vec& vecTA2 = ph.GetTA2(); + + while(1) + { + std::cout << "q = "; + double dq; + std::cin >> dq; + + std::ofstream ofstrPlot("plt_phonon.gpl"); + ofstrPlot << "set term wxt\n"; + ofstrPlot << "plot \"-\" pt 7\n"; + + const t_vec vecQ = vecBragg + vecTA2*dq; + for(double dE=-20.; dE<20.; dE += 0.25) + { + double dS = ph(vecQ[0], vecQ[1], vecQ[2], dE); + ofstrPlot << dE << " " << dS << "\n"; + } + ofstrPlot << "e\n"; + ofstrPlot.flush(); + ofstrPlot.close(); + + std::system("gnuplot -persist plt_phonon.gpl"); + } + return 0; +} diff --git a/tools/monteconvo/xmconv_main.cpp b/tools/monteconvo/xmconv_main.cpp new file mode 100644 index 0000000..b3ed5a3 --- /dev/null +++ b/tools/monteconvo/xmconv_main.cpp @@ -0,0 +1,29 @@ +/* + * xmonteconvo + * @author tweber + * @date aug-2015 + * @copyright GPLv2 + */ + +#include +#include +#include +#include +#include "ConvoDlg.h" + + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + std::setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::English); + + QSettings m_settings("tobis_stuff", "takin"); + ConvoDlg dlg(nullptr, &m_settings); + dlg.setWindowFlags(Qt::Window); + dlg.show(); + + int iRet = app.exec(); + return iRet; +} diff --git a/tools/montereso/res.cpp b/tools/montereso/res.cpp new file mode 100644 index 0000000..f599a0f --- /dev/null +++ b/tools/montereso/res.cpp @@ -0,0 +1,194 @@ +/** + * Monte-Carlo resolution calculation + * + * @author Tobias Weber + * @date July 2012, Sep. 2014 + * @license GPLv2 + * + * (based on Mcstas' 'mcresplot.pl' perl program: www.mcstas.org + * and the rescal5 matlab program: http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/) + */ + +#include "res.h" + +#include "tlibs/math/neutrons.h" +#include "tlibs/log/log.h" + +#include +#include +#include +#include +#include +#include + +using namespace ublas; + + +/* + * this function tries to be a 1:1 C++ reimplementation of the Perl function + * 'read_mcstas_res' of the McStas 'mcresplot' program + */ +Resolution calc_res(const std::vector>& Q_vec, + const vector& Q_avg, const std::vector* pp_vec) +{ + vector Q_dir = tl::make_vec({Q_avg[0], Q_avg[1], Q_avg[2]}); + Q_dir = Q_dir / norm_2(Q_dir); + + vector vecUp = tl::make_vec({0., 0., 1.}); + vector Q_perp = tl::cross_3(vecUp, Q_dir); + vecUp = tl::cross_3(Q_dir, Q_perp); + + Q_perp[0]=Q_dir[1]; Q_perp[1]=Q_dir[0]; Q_perp[2]=Q_dir[2]; + + + matrix trafo(4, 4); + trafo(0,0)=Q_dir[0]; trafo(1,0)=Q_dir[1]; trafo(2,0)=Q_dir[2]; + trafo(0,1)=Q_perp[0]; trafo(1,1)=Q_perp[1]; trafo(2,1)=Q_perp[2]; + trafo(0,2)=vecUp[0]; trafo(1,2)=vecUp[1]; trafo(2,2)=vecUp[2]; + + trafo(3,0)=trafo(0,3)=trafo(3,1)=trafo(1,3)=trafo(3,2)=trafo(2,3) = 0.; + trafo(3,3) = 1.; + + //std::cout << "trafo = " << trafo << std::endl; + + Resolution reso; + reso.Q_avg = prod(trans(trafo), Q_avg); + + matrix& res = reso.res; + matrix& cov = reso.cov; + res.resize(4,4,0); + cov.resize(4,4,0); + + cov = tl::covariance(Q_vec, pp_vec); + cov = tl::transform>(cov, trafo, true); + + tl::log_info("Covariance matrix: ", cov); + reso.bHasRes = tl::inverse(cov, res); + + if(reso.bHasRes) + { + reso.dQ.resize(4, 0); + for(int iQ=0; iQ<4; ++iQ) + reso.dQ[iQ] = tl::SIGMA2HWHM/sqrt(res(iQ,iQ)); + + tl::log_info("Resolution matrix: ", res); + + const vector& dQ = reso.dQ; + const vector& Q_avg = reso.Q_avg; + + std::ostringstream ostrVals; + ostrVals << "Gaussian HWHM values: "; + std::copy(dQ.begin(), dQ.end(), std::ostream_iterator(ostrVals, ", ")); + + std::ostringstream ostrElli; + ostrElli << "Ellipsoid offsets: "; + std::copy(Q_avg.begin(), Q_avg.end(), std::ostream_iterator(ostrElli, ", ")); + + tl::log_info(ostrVals.str()); + tl::log_info(ostrElli.str()); + } + else + { + tl::log_err("Covariance matrix could not be inverted!"); + } + + return reso; +} + + +Resolution calc_res(unsigned int uiLen, + const t_real_reso *_Q_x, const t_real_reso *_Q_y, const t_real_reso *_Q_z, + const t_real_reso *_E) +{ + vector Q_avg(4); + Q_avg[0] = Q_avg[1] = Q_avg[2] = Q_avg[3] = 0.; + + std::vector> Q_vec; + Q_vec.reserve(uiLen); + + for(unsigned int uiRow=0; uiRow Q(4); + + Q[0] = _Q_x[uiRow]; + Q[1] = _Q_y[uiRow]; + Q[2] = _Q_z[uiRow]; + Q[3] = _E[uiRow]; + + Q_avg += Q; + + Q_vec.push_back(Q); + } + Q_avg /= t_real_reso(uiLen); + tl::log_info("Average Q vector: ", Q_avg); + + return calc_res(Q_vec, Q_avg); +} + + +/* + * this function tries to be a 1:1 C++ reimplementation of the Perl function + * 'read_mcstas_res' of the McStas 'mcresplot' program + */ +Resolution calc_res(unsigned int uiLen, + const t_real_reso *_ki_x, const t_real_reso *_ki_y, const t_real_reso *_ki_z, + const t_real_reso *_kf_x, const t_real_reso *_kf_y, const t_real_reso *_kf_z, + const t_real_reso *_p_i, const t_real_reso *_p_f) +{ + tl::log_info("Calculating resolution..."); + + std::vector> Q_vec; + std::vector p_vec; + Q_vec.reserve(uiLen); + p_vec.reserve(uiLen); + + std::unique_ptr ptr_dE_vec(new t_real_reso[uiLen]); + + t_real_reso *dE_vec = ptr_dE_vec.get(); + + + const t_real_reso pi_max = _p_i ? *std::max_element(_p_i, _p_i+uiLen) : 1.; + const t_real_reso pf_max = _p_f ? *std::max_element(_p_f, _p_f+uiLen) : 1.; + const t_real_reso p_max = fabs(pi_max*pf_max); + + + vector Q_avg(4); + Q_avg[0] = Q_avg[1] = Q_avg[2] = Q_avg[3] = 0.; + + t_real_reso p_sum = 0.; + + for(unsigned int uiRow=0; uiRow Q(3); + t_real_reso p; + + p = (_p_i && _p_f) ? fabs(_p_i[uiRow]*_p_f[uiRow]) : 1.; + p /= p_max; // normalize p to 0..1 + p_sum += p; + + t_real_reso &dE = dE_vec[uiRow]; + + vector ki(3), kf(3); + ki[0]=_ki_x[uiRow]; ki[1]=_ki_y[uiRow]; ki[2]=_ki_z[uiRow]; + kf[0]=_kf_x[uiRow]; kf[1]=_kf_y[uiRow]; kf[2]=_kf_z[uiRow]; + + Q = ki - kf; + t_real_reso Ei = tl::get_KSQ2E() * inner_prod(ki, ki); + t_real_reso Ef = tl::get_KSQ2E() * inner_prod(kf, kf); + dE = Ei - Ef; + + // insert the energy into the Q vector + Q.resize(4, true); + Q[3] = dE; + + Q_avg += Q*p; + + Q_vec.push_back(Q); + p_vec.push_back(p); + } + Q_avg /= p_sum; + tl::log_info("Average Q vector: ", Q_avg); + + + return calc_res(Q_vec, Q_avg, &p_vec); +} diff --git a/tools/montereso/res.h b/tools/montereso/res.h new file mode 100644 index 0000000..0b3bd16 --- /dev/null +++ b/tools/montereso/res.h @@ -0,0 +1,49 @@ +/** + * Monte-Carlo resolution calculation + * + * @author Tobias Weber + * @date July 2012, Sep. 2014 + * @license GPLv2 + * + * (based on Mcstas' 'mcresplot.pl' perl program: www.mcstas.org + * and the rescal5 matlab program: http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/) + */ + +#ifndef __MONTERES_H__ +#define __MONTERES_H__ + +#include "../res/defs.h" +#include "tlibs/math/linalg.h" +namespace ublas = boost::numeric::ublas; + +struct Resolution +{ + // covariance matrix + ublas::matrix cov; + + // resolution matrix + bool bHasRes; + ublas::matrix res; + + // half-widths + ublas::vector dQ; // in 1/A and meV + + // ellipse origin + ublas::vector Q_avg; +}; + + +Resolution calc_res(const std::vector>& Q_vec, + const ublas::vector& Q_avg, + const std::vector* pp_vec = 0); + +Resolution calc_res(unsigned int uiLen, + const t_real_reso *_Q_x, const t_real_reso *_Q_y, const t_real_reso *_Q_z, + const t_real_reso *_E); + +Resolution calc_res(unsigned int uiLen, + const t_real_reso *ki_x, const t_real_reso *ki_y, const t_real_reso *ki_z, + const t_real_reso *kf_x, const t_real_reso *kf_y, const t_real_reso *kf_z, + const t_real_reso *p_i=0, const t_real_reso *p_f=0); + +#endif diff --git a/tools/montereso/res_main.cpp b/tools/montereso/res_main.cpp new file mode 100644 index 0000000..ee19057 --- /dev/null +++ b/tools/montereso/res_main.cpp @@ -0,0 +1,289 @@ +/* + * Montereso + * @author tweber + * @date 2012, 22-sep-2014 + * @license GPLv2 + */ + +#include "res.h" +#include "tlibs/log/log.h" +#include "tlibs/string/string.h" +#include "dialogs/EllipseDlg.h" + +#include +#include +#include +#include +#include + +using namespace ublas; + +static void add_param(std::unordered_map& map, const std::string& strLine) +{ + std::string str = strLine.substr(1); + + std::pair pair = tl::split_first(str, ":", true); + if(pair.first == "Param") + { + std::pair pairParam = tl::split_first(pair.second, "=", true); + pair.first = pair.first + "_" + pairParam.first; + pair.second = pairParam.second; + } + + map.insert(pair); +} + +template +static void print_map(std::ostream& ostr, const t_map& map) +{ + for(typename t_map::const_iterator iter=map.begin(); iter!=map.end(); ++iter) + ostr << (*iter).first << ": " << (*iter).second << "\n"; +} + +enum class FileType +{ + NEUTRON_Q_LIST, + NEUTRON_KIKF_LIST, + + RESOLUTION_MATRIX, + COVARIANCE_MATRIX, + + UNKNOWN +}; + +static bool load_mat(const char* pcFile, Resolution& reso, FileType ft) +{ + std::ifstream ifstr(pcFile); + if(!ifstr.is_open()) + { + tl::log_err("Cannot open \"", pcFile, "\"."); + return 0; + } + + matrix& res = reso.res; + matrix& cov = reso.cov; + res.resize(4,4,0); + cov.resize(4,4,0); + + if(ft == FileType::COVARIANCE_MATRIX) + { + for(unsigned int i=0; i<4; ++i) + for(unsigned int j=0; j<4; ++j) + ifstr >> cov(i,j); + + reso.bHasRes = tl::inverse(cov, res); + } + else if(ft == FileType::RESOLUTION_MATRIX) + { + for(unsigned int i=0; i<4; ++i) + for(unsigned int j=0; j<4; ++j) + ifstr >> res(i,j); + + reso.bHasRes = tl::inverse(res, cov); + } + + tl::log_info("Covariance matrix: ", cov); + tl::log_info("Resolution matrix: ", res); + tl::log_info("Matrix valid: ", reso.bHasRes); + + if(reso.bHasRes) + { + vector& dQ = reso.dQ; + + dQ.resize(4, 0); + reso.Q_avg.resize(4, 0); + for(int iQ=0; iQ<4; ++iQ) + dQ[iQ] = tl::SIGMA2HWHM/sqrt(res(iQ,iQ)); + + std::ostringstream ostrVals; + ostrVals << "Gaussian HWHM values: "; + std::copy(dQ.begin(), dQ.end(), std::ostream_iterator(ostrVals, ", ")); + + tl::log_info(ostrVals.str()); + } + + return reso.bHasRes; +} + +static bool load_mc_list(const char* pcFile, Resolution& res) +{ + FileType ft = FileType::NEUTRON_Q_LIST; + + std::ifstream ifstr(pcFile); + if(!ifstr.is_open()) + { + tl::log_err("Cannot open \"", pcFile, "\"."); + return 0; + } + + // neutron Q list + std::vector vecQx, vecQy, vecQz, vecE; + + // neutron ki, kf list + std::vector vecKi[3], vecKf[3], vecPos[3]; + std::vector vecPi, vecPf; + std::string strLine; + + std::unordered_map mapParams; + + bool bEndOfHeader = 0; + + unsigned int uiNumNeutr = 0; + while(std::getline(ifstr, strLine)) + { + tl::trim(strLine); + if(strLine.length()==0) + continue; + else if(strLine[0]=='#') + { + add_param(mapParams, strLine); + continue; + } + + if(!bEndOfHeader) + { + bEndOfHeader = 1; + + try + { + if(mapParams.at("variables") == "ki_x ki_y ki_z kf_x kf_y kf_z x y z p_i p_f") + { + tl::log_info("File is a ki, kf list."); + ft = FileType::NEUTRON_KIKF_LIST; + } + } + catch(const std::out_of_range& ex) + { + tl::log_info("File is a Q list."); + ft = FileType::NEUTRON_Q_LIST; + } + } + + std::istringstream istr(strLine); + + if(ft == FileType::NEUTRON_Q_LIST) + { + t_real_reso dQx=0., dQy=0., dQz=0., dE=0.; + + istr >> dQx >> dQy >> dQz >> dE; + + vecQx.push_back(dQx); + vecQy.push_back(dQy); + vecQz.push_back(dQz); + vecE.push_back(dE); + } + else if(ft == FileType::NEUTRON_KIKF_LIST) + { + t_real_reso dKi[3], dKf[3], dPos[3], dPi=0., dPf=0.; + + istr >> dKi[0] >> dKi[2] >> dKi[1]; + istr >> dKf[0] >> dKf[2] >> dKf[1]; + istr >> dPos[0] >> dPos[2] >> dPos[1]; + istr >> dPi >> dPf; + + dKi[1] = -dKi[1]; + dKf[1] = -dKf[1]; + dPos[1] = -dPos[1]; + + for(short s=0; s<3; ++s) + { + vecKi[s].push_back(dKi[s]); + vecKf[s].push_back(dKf[s]); + vecPos[s].push_back(dPos[s]); + } + vecPi.push_back(dPi); + vecPf.push_back(dPf); + } + + ++uiNumNeutr; + } + + tl::log_info("Number of neutrons in file: ", uiNumNeutr); + //print_map(std::cout, mapParams); + + if(ft == FileType::NEUTRON_Q_LIST) + res = calc_res(vecQx.size(), vecQx.data(), vecQy.data(), vecQz.data(), vecE.data()); + else if(ft == FileType::NEUTRON_KIKF_LIST) + res = calc_res(vecPi.size(), + vecKi[0].data(), vecKi[1].data(), vecKi[2].data(), + vecKf[0].data(), vecKf[1].data(), vecKf[2].data(), + vecPi.data(), vecPf.data()); + + if(!res.bHasRes) + { + tl::log_err("Cannot calculate resolution matrix."); + return 0; + } + + return 1; +} + +static EllipseDlg* show_ellipses(const Resolution& res) +{ + EllipseDlg* pdlg = new EllipseDlg(0); + pdlg->show(); + + matrix matDummy; + vector vecDummy; + vector vecZero = zero_vector(4); + + EllipseDlgParams params; + params.reso = &res.res; + pdlg->SetParams(params); + + return pdlg; +} + + +int main(int argc, char **argv) +{ + std::setlocale(LC_ALL, "C"); + if(argc <= 1) + { + std::ostringstream ostr; + ostr << "Usage: " << argv[0] << " [-r,-c] \n" + << "\t-r\t contains resolution matrix\n" + << "\t-c\t contains covariance matrix\n" + << "\t\t contains Q or ki,kf list"; + + tl::log_err("No input file given.\n", ostr.str()); + return -1; + } + + const char* pcFile = argv[argc-1]; + + FileType ft = FileType::UNKNOWN; + for(int iArg=1; iArg +#include + + +using t_real = t_real_glob; + +static inline void usage(const char* pcProg) +{ + tl::log_err("Usage:\n", "\t", pcProg, " "); +} + + +static inline void extract_pos(const char* pcIn, const char* pcOut) +{ + std::shared_ptr> ptrInstr( + tl::FileInstrBase::LoadInstr(pcIn)); + tl::FileInstrBase *pInstr = ptrInstr.get(); + + if(!pInstr) + { + tl::log_err("Cannot load scan file \"", pcIn, "\"."); + return; + } + + + std::ofstream ofstr(pcOut); + if(!ofstr.is_open()) + { + tl::log_err("Cannot load output file \"", pcOut, "\"."); + return; + } + + ofstr.precision(16); + ofstr << "#\n"; + ofstr << "# num_neutrons: 1000\n"; + ofstr << "# algo: 1\n"; + ofstr << "#\n"; + ofstr << "# fixed_ki: " << pInstr->IsKiFixed() << "\n"; + ofstr << "# kfix: " << pInstr->GetKFix() << "\n"; + ofstr << "#\n"; + ofstr << "# h k l E data follows\n"; + ofstr << "#\n"; + + tl::log_info("Extracting ", pInstr->GetScanCount(), " scan positions."); + for(std::size_t iScan=0; iScanGetScanCount(); ++iScan) + { + std::array arrPos = pInstr->GetScanHKLKiKf(iScan); + t_real dh = arrPos[0]; + t_real dk = arrPos[1]; + t_real dl = arrPos[2]; + t_real dki = arrPos[3]; + t_real dkf = arrPos[4]; + t_real dE = (tl::k2E(dki/tl::angstrom) - tl::k2E(dkf/tl::angstrom))/tl::meV; + + ofstr << std::left << std::setw(20) << dh << " " + << std::left << std::setw(20) << dk << " " + << std::left << std::setw(20) << dl << " " + << std::left << std::setw(20) << dE << std::endl; + } + + tl::log_info("Done."); + ofstr.close(); +} + + +int main(int argc, char** argv) +{ + if(argc < 3) + { + usage(argv[0]); + return -1; + } + + extract_pos(argv[1], argv[2]); + return 0; +} diff --git a/tools/res/ResoDlg.cpp b/tools/res/ResoDlg.cpp new file mode 100644 index 0000000..7606918 --- /dev/null +++ b/tools/res/ResoDlg.cpp @@ -0,0 +1,1332 @@ +/** + * resolution calculation + * @author tweber + * @date 2013 - 2016 + * @license GPLv2 + */ + +#include "ResoDlg.h" +#include +#include +#include +//#include + +#include "tlibs/string/string.h" +#include "tlibs/helper/flags.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/helper/misc.h" +#include "tlibs/math/math.h" +#include "tlibs/math/lattice.h" + +#include "libs/globals.h" +#include "mc.h" + +#include +#include +#include +#include + +using t_mat = ublas::matrix; +using t_vec = ublas::vector; + +static const auto angs = tl::get_one_angstrom(); +static const auto rads = tl::get_one_radian(); +static const auto meV = tl::get_one_meV(); +static const auto cm = tl::get_one_centimeter(); +static const auto meters = tl::get_one_meter(); +static const auto sec = tl::get_one_second(); + + +ResoDlg::ResoDlg(QWidget *pParent, QSettings* pSettings) + : QDialog(pParent), m_bDontCalc(1), m_pSettings(pSettings) +{ + setupUi(this); + if(m_pSettings) + { + QFont font; + if(m_pSettings->contains("main/font_gen") && font.fromString(m_pSettings->value("main/font_gen", "").toString())) + setFont(font); + } + + btnSave->setIcon(load_icon("res/document-save.svg")); + btnLoad->setIcon(load_icon("res/document-open.svg")); + + setupAlgos(); + QObject::connect(comboAlgo, SIGNAL(currentIndexChanged(int)), this, SLOT(AlgoChanged())); + comboAlgo->setCurrentIndex(1); + + groupGuide->setChecked(false); + + m_vecSpinBoxes = {spinMonod, spinMonoMosaic, spinAnad, + spinAnaMosaic, spinSampleMosaic, + spinHCollMono, spinHCollBSample, + spinHCollASample, spinHCollAna, spinVCollMono, + spinVCollBSample, spinVCollASample, spinVCollAna, + spinMonoRefl, spinAnaEffic, + + spinMonoW, spinMonoH, spinMonoThick, spinMonoCurvH, spinMonoCurvV, + spinSampleW_Q, spinSampleW_perpQ, spinSampleH, + spinAnaW, spinAnaH, spinAnaThick, spinAnaCurvH, spinAnaCurvV, + spinSrcW, spinSrcH, + spinGuideDivH, spinGuideDivV, + spinDetW, spinDetH, + spinDistMonoSample, spinDistSampleAna, spinDistAnaDet, spinDistSrcMono, + + spinMonoMosaicV, spinAnaMosaicV, + spinSamplePosX, spinSamplePosY, spinSamplePosZ, + + spinDistTofPulseMono, spinDistTofMonoSample, spinDistTofSampleDet, + spinDistTofPulseMonoSig, spinDistTofMonoSampleSig, spinDistTofSampleDetSig, + spinTofPulseSig, spinTofMonoSig, spinTofDetSig, + spinTof2thI, spinTofphI, spinTofphF, + spinTof2thISig, spinTof2thFSig, spinTofphISig, spinTofphFSig, + + spinSigKi, spinSigKi_perp, spinSigKi_z, + spinSigKf, spinSigKf_perp, spinSigKf_z, + }; + + m_vecSpinNames = {"reso/mono_d", "reso/mono_mosaic", "reso/ana_d", + "reso/ana_mosaic", "reso/sample_mosaic", + "reso/h_coll_mono", "reso/h_coll_before_sample", + "reso/h_coll_after_sample", "reso/h_coll_ana", + "reso/v_coll_mono", "reso/v_coll_before_sample", + "reso/v_coll_after_sample", "reso/v_coll_ana", + "reso/mono_refl", "reso/ana_effic", + + "reso/pop_mono_w", "reso/pop_mono_h", "reso/pop_mono_thick", "reso/pop_mono_curvh", "reso/pop_mono_curvv", + "reso/pop_sample_wq", "reso/pop_sampe_wperpq", "reso/pop_sample_h", + "reso/pop_ana_w", "reso/pop_ana_h", "reso/pop_ana_thick", "reso/pop_ana_curvh", "reso/pop_ana_curvv", + "reso/pop_src_w", "reso/pop_src_h", + "reso/pop_guide_divh", "reso/pop_guide_divv", + "reso/pop_det_w", "reso/pop_det_h", + "reso/pop_dist_mono_sample", "reso/pop_dist_sample_ana", "reso/pop_dist_ana_det", "reso/pop_dist_src_mono", + + "reso/eck_mono_mosaic_v", "reso/eck_ana_mosaic_v", + "reso/eck_sample_pos_x", "reso/eck_sample_pos_y", "reso/eck_sample_pos_z", + + "reso/viol_dist_pulse_mono", "reso/viol_dist_mono_sample", "reso/viol_dist_sample_det", + "reso/viol_dist_pulse_mono_sig", "reso/viol_dist_mono_sample_sig", "reso/viol_dist_sample_det_sig", + "reso/viol_time_pulse_sig", "reso/viol_time_mono_sig", "reso/viol_time_det_sig", + "reso/viol_angle_tt_i", "reso/viol_angle_ph_i", "reso/viol_angle_ph_f", + "reso/viol_angle_tt_i_sig", "reso/viol_angle_tt_f_sig", "reso/viol_angle_ph_i_sig", "reso/viol_angle_ph_f_sig", + + "reso/simple_sig_ki", "reso/simple_sig_ki_perp", "reso/simple_sig_ki_z", + "reso/simple_sig_kf", "reso/simple_sig_kf_perp", "reso/simple_sig_kf_z", + }; + + m_vecPosEditBoxes = {editE, editQ, editKi, editKf}; + m_vecPosEditNames = {"reso/E", "reso/Q", "reso/ki", "reso/kf"}; + + m_vecCheckBoxes = {}; + m_vecCheckNames = {}; + + + m_vecRadioPlus = {radioMonoScatterPlus, radioAnaScatterPlus, + radioSampleScatterPlus, + radioSampleCub, radioSrcRect, radioDetRect, + radioTofDetSph}; + m_vecRadioMinus = {radioMonoScatterMinus, radioAnaScatterMinus, + radioSampleScatterMinus, radioSampleCyl, + radioSrcCirc, radioDetCirc, + radioTofDetCyl}; + m_vecRadioNames = {"reso/mono_scatter_sense", "reso/ana_scatter_sense", + "reso/sample_scatter_sense", "reso/pop_sample_cuboid", + "reso/pop_source_rect", "reso/pop_det_rect", + "reso/viol_det_sph"}; + + m_vecComboBoxes = {/*comboAlgo,*/ + comboAnaHori, comboAnaVert, + comboMonoHori, comboMonoVert}; + m_vecComboNames = {/*"reso/algo",*/ + "reso/pop_ana_use_curvh", "reso/pop_ana_use_curvv", + "reso/pop_mono_use_curvh", "reso/pop_mono_use_curvv"}; + + ReadLastConfig(); + + QObject::connect(groupGuide, SIGNAL(toggled(bool)), this, SLOT(Calc())); + + for(QDoubleSpinBox* pSpinBox : m_vecSpinBoxes) + QObject::connect(pSpinBox, SIGNAL(valueChanged(double)), this, SLOT(Calc())); + for(QLineEdit* pEditBox : m_vecPosEditBoxes) + QObject::connect(pEditBox, SIGNAL(textEdited(const QString&)), this, SLOT(RefreshQEPos())); + for(QRadioButton* pRadio : m_vecRadioPlus) + QObject::connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(Calc())); + for(QComboBox* pCombo : m_vecComboBoxes) + QObject::connect(pCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(Calc())); + QObject::connect(comboAlgo, SIGNAL(currentIndexChanged(int)), this, SLOT(Calc())); + + + connect(checkElli4dAutoCalc, SIGNAL(stateChanged(int)), this, SLOT(checkAutoCalcElli4dChanged())); + connect(btnCalcElli4d, SIGNAL(clicked()), this, SLOT(CalcElli4d())); + connect(btnMCGenerate, SIGNAL(clicked()), this, SLOT(MCGenerate())); + connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(ButtonBoxClicked(QAbstractButton*))); + connect(btnSave, SIGNAL(clicked()), this, SLOT(SaveRes())); + connect(btnLoad, SIGNAL(clicked()), this, SLOT(LoadRes())); + + m_bDontCalc = 0; + RefreshQEPos(); + //Calc(); +} + +ResoDlg::~ResoDlg() {} + +void ResoDlg::setupAlgos() +{ + comboAlgo->addItem("TAS: Cooper-Nathans", static_cast(ResoAlgo::CN)); + comboAlgo->addItem("TAS: Popovici", static_cast(ResoAlgo::POP)); + comboAlgo->addItem("TAS: Eckold-Sobolev", static_cast(ResoAlgo::ECK)); + comboAlgo->insertSeparator(3); + comboAlgo->addItem("TOF: Violini", static_cast(ResoAlgo::VIOL)); + comboAlgo->insertSeparator(5); + comboAlgo->addItem("Simple", static_cast(ResoAlgo::SIMPLE)); +} + +void ResoDlg::SaveRes() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + strDirLast = m_pSettings->value("reso/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getSaveFileName(this, + "Save resolution configuration", + strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + + if(qstrFile == "") + return; + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + std::map mapConf; + Save(mapConf, strXmlRoot); + + tl::Prop xml; + xml.Add(mapConf); + bool bOk = xml.Save(strFile.c_str(), tl::PropType::XML); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not save resolution file."); + + if(bOk && m_pSettings) + m_pSettings->setValue("reso/last_dir", QString(strDir.c_str())); +} + +void ResoDlg::LoadRes() +{ + const std::string strXmlRoot("taz/"); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = "."; + if(m_pSettings) + strDirLast = m_pSettings->value("reso/last_dir", ".").toString(); + QString qstrFile = QFileDialog::getOpenFileName(this, + "Open resolution configuration...", + strDirLast, + "TAZ files (*.taz *.TAZ)", nullptr, + fileopt); + if(qstrFile == "") + return; + + + std::string strFile = qstrFile.toStdString(); + std::string strDir = tl::get_dir(strFile); + + tl::Prop xml; + if(!xml.Load(strFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not load resolution file."); + return; + } + + Load(xml, strXmlRoot); + if(m_pSettings) + m_pSettings->setValue("reso/last_dir", QString(strDir.c_str())); + +} + +void ResoDlg::RefreshQEPos() +{ + try + { + tl::t_wavenumber_si Q = editQ->text().toDouble() / angs; + tl::t_wavenumber_si ki = editKi->text().toDouble() / angs; + tl::t_wavenumber_si kf = editKf->text().toDouble() / angs; + //t_real_reso dE = editE->text().toDouble(); + tl::t_energy_si E = tl::get_energy_transfer(ki, kf); + + tl::t_angle_si kiQ = tl::get_angle_ki_Q(ki, kf, Q, 1); + tl::t_angle_si kfQ = tl::get_angle_kf_Q(ki, kf, Q, 1); + tl::t_angle_si twotheta = tl::get_sample_twotheta(ki, kf, Q, 1); + + const t_real_reso dMono = spinMonod->value(); + const t_real_reso dAna = spinAnad->value(); + + m_simpleparams.ki = m_tofparams.ki = m_tasparams.ki = ki; + m_simpleparams.kf = m_tofparams.kf = m_tasparams.kf = kf; + m_simpleparams.E = m_tofparams.E = m_tasparams.E = E; + m_simpleparams.Q = m_tofparams.Q = m_tasparams.Q = Q; + + m_simpleparams.twotheta = m_tofparams.twotheta = m_tasparams.twotheta = twotheta; + m_simpleparams.angle_ki_Q = m_tofparams.angle_ki_Q = m_tasparams.angle_ki_Q = kiQ; + m_simpleparams.angle_kf_Q = m_tofparams.angle_kf_Q = m_tasparams.angle_kf_Q = kfQ; + + m_tasparams.thetam = 0.5 * tl::get_mono_twotheta(ki, dMono*angs, 1); + m_tasparams.thetaa = 0.5 * tl::get_mono_twotheta(kf, dAna*angs, 1); + +#ifndef NDEBUG + tl::log_debug("Manually changed parameters: ", + "ki=",ki, ", kf=", kf, ", Q=",Q, ", E=", E, + ", tt=", twotheta, ", kiQ=", kiQ, ", kfQ=", kfQ, "."); +#endif + Calc(); + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + } +} + +void ResoDlg::Calc() +{ + try + { + m_bEll4dCurrent = 0; + if(m_bDontCalc) return; + + EckParams &cn = m_tasparams; + ViolParams &tof = m_tofparams; + SimpleResoParams &simple = m_simpleparams; + + ResoResults &res = m_res; + + // CN + cn.mono_d = t_real_reso(spinMonod->value()) * angs; + cn.mono_mosaic = t_real_reso(tl::m2r(spinMonoMosaic->value())) * rads; + cn.ana_d = t_real_reso(spinAnad->value()) * angs; + cn.ana_mosaic = t_real_reso(tl::m2r(spinAnaMosaic->value())) * rads; + cn.sample_mosaic = t_real_reso(tl::m2r(spinSampleMosaic->value())) * rads; + + cn.dmono_sense = (radioMonoScatterPlus->isChecked() ? +1. : -1.); + cn.dana_sense = (radioAnaScatterPlus->isChecked() ? +1. : -1.); + cn.dsample_sense = (radioSampleScatterPlus->isChecked() ? +1. : -1.); + //std::cout << "sample sense: " << cn.dsample_sense << std::endl; + //if(spinQ->value() < 0.) + // cn.dsample_sense = -cn.dsample_sense; + + cn.coll_h_pre_mono = t_real_reso(tl::m2r(spinHCollMono->value())) * rads; + cn.coll_h_pre_sample = t_real_reso(tl::m2r(spinHCollBSample->value())) * rads; + cn.coll_h_post_sample = t_real_reso(tl::m2r(spinHCollASample->value())) * rads; + cn.coll_h_post_ana = t_real_reso(tl::m2r(spinHCollAna->value())) * rads; + + cn.coll_v_pre_mono = t_real_reso(tl::m2r(spinVCollMono->value())) * rads; + cn.coll_v_pre_sample = t_real_reso(tl::m2r(spinVCollBSample->value())) * rads; + cn.coll_v_post_sample = t_real_reso(tl::m2r(spinVCollASample->value())) * rads; + cn.coll_v_post_ana = t_real_reso(tl::m2r(spinVCollAna->value())) * rads; + + cn.dmono_refl = spinMonoRefl->value(); + cn.dana_effic = spinAnaEffic->value(); + + + // Position + /*cn.ki = t_real_reso(editKi->text().toDouble()) / angs; + cn.kf = t_real_reso(editKf->text().toDouble()) / angs; + cn.Q = t_real_reso(editQ->text().toDouble()) / angs; + cn.E = t_real_reso(editE->text().toDouble()) * meV; + //cn.E = tl::get_energy_transfer(cn.ki, cn.kf); + //std::cout << "E = " << editE->text().toStdString() << std::endl;*/ + + + // Pop + cn.mono_w = t_real_reso(spinMonoW->value()) * cm; + cn.mono_h = t_real_reso(spinMonoH->value()) * cm; + cn.mono_thick = t_real_reso(spinMonoThick->value()) * cm; + cn.mono_curvh = t_real_reso(spinMonoCurvH->value()) * cm; + cn.mono_curvv = t_real_reso(spinMonoCurvV->value()) * cm; + cn.bMonoIsCurvedH = cn.bMonoIsCurvedV = 0; + cn.bMonoIsOptimallyCurvedH = cn.bMonoIsOptimallyCurvedV = 0; + spinMonoCurvH->setEnabled(0); spinMonoCurvV->setEnabled(0); + + if(comboMonoHori->currentIndex()==2) + { + cn.bMonoIsCurvedH = 1; + spinMonoCurvH->setEnabled(1); + } + else if(comboMonoHori->currentIndex()==1) + cn.bMonoIsCurvedH = cn.bMonoIsOptimallyCurvedH = 1; + + if(comboMonoVert->currentIndex()==2) + { + cn.bMonoIsCurvedV = 1; + spinMonoCurvV->setEnabled(1); + } + else if(comboMonoVert->currentIndex()==1) + cn.bMonoIsCurvedV = cn.bMonoIsOptimallyCurvedV = 1; + + cn.ana_w = t_real_reso(spinAnaW->value()) *cm; + cn.ana_h = t_real_reso(spinAnaH->value()) * cm; + cn.ana_thick = t_real_reso(spinAnaThick->value()) * cm; + cn.ana_curvh = t_real_reso(spinAnaCurvH->value()) * cm; + cn.ana_curvv = t_real_reso(spinAnaCurvV->value()) * cm; + cn.bAnaIsCurvedH = cn.bAnaIsCurvedV = 0; + cn.bAnaIsOptimallyCurvedH = cn.bAnaIsOptimallyCurvedV = 0; + spinAnaCurvH->setEnabled(0); spinAnaCurvV->setEnabled(0); + + if(comboAnaHori->currentIndex()==2) + { + cn.bAnaIsCurvedH = 1; + spinAnaCurvH->setEnabled(1); + } + else if(comboAnaHori->currentIndex()==1) + cn.bAnaIsCurvedH = cn.bAnaIsOptimallyCurvedH = 1; + + if(comboAnaVert->currentIndex()==2) + { + cn.bAnaIsCurvedV = 1; + spinAnaCurvV->setEnabled(1); + } + else if(comboAnaVert->currentIndex()==1) + cn.bAnaIsCurvedV = cn.bAnaIsOptimallyCurvedV = 1; + + cn.bSampleCub = radioSampleCub->isChecked(); + cn.sample_w_q = t_real_reso(spinSampleW_Q->value()) * cm; + cn.sample_w_perpq = t_real_reso(spinSampleW_perpQ->value()) * cm; + cn.sample_h = t_real_reso(spinSampleH->value()) * cm; + + cn.bSrcRect = radioSrcRect->isChecked(); + cn.src_w = t_real_reso(spinSrcW->value()) * cm; + cn.src_h = t_real_reso(spinSrcH->value()) * cm; + + cn.bDetRect = radioDetRect->isChecked(); + cn.det_w = t_real_reso(spinDetW->value()) * cm; + cn.det_h = t_real_reso(spinDetH->value()) * cm; + + cn.bGuide = groupGuide->isChecked(); + cn.guide_div_h = t_real_reso(tl::m2r(spinGuideDivH->value())) * rads; + cn.guide_div_v = t_real_reso(tl::m2r(spinGuideDivV->value())) * rads; + + cn.dist_mono_sample = t_real_reso(spinDistMonoSample->value()) * cm; + cn.dist_sample_ana = t_real_reso(spinDistSampleAna->value()) * cm; + cn.dist_ana_det = t_real_reso(spinDistAnaDet->value()) * cm; + cn.dist_src_mono = t_real_reso(spinDistSrcMono->value()) * cm; + + + // Eck + cn.mono_mosaic_v = t_real_reso(tl::m2r(spinMonoMosaicV->value())) * rads; + cn.ana_mosaic_v = t_real_reso(tl::m2r(spinAnaMosaicV->value())) * rads; + cn.pos_x = t_real_reso(spinSamplePosX->value()) * cm; + cn.pos_y = t_real_reso(spinSamplePosY->value()) * cm; + cn.pos_z = t_real_reso(spinSamplePosZ->value()) * cm; + + // TODO + cn.mono_numtiles_h = 1; + cn.mono_numtiles_v = 1; + cn.ana_numtiles_h = 1; + cn.ana_numtiles_v = 1; + + + // TOF + tof.len_pulse_mono = t_real_reso(spinDistTofPulseMono->value()) * cm; + tof.len_mono_sample = t_real_reso(spinDistTofMonoSample->value()) * cm; + tof.len_sample_det = t_real_reso(spinDistTofSampleDet->value()) * cm; + + tof.sig_len_pulse_mono = t_real_reso(spinDistTofPulseMonoSig->value()) * cm; + tof.sig_len_mono_sample = t_real_reso(spinDistTofMonoSampleSig->value()) * cm; + tof.sig_len_sample_det = t_real_reso(spinDistTofSampleDetSig->value()) * cm; + + tof.sig_pulse = t_real_reso(spinTofPulseSig->value() * 1e-6) * sec; + tof.sig_mono = t_real_reso(spinTofMonoSig->value() * 1e-6) * sec; + tof.sig_det = t_real_reso(spinTofDetSig->value() * 1e-6) * sec; + + tof.twotheta_i = tl::d2r(t_real_reso(spinTof2thI->value())) * rads; + tof.angle_outplane_i = tl::d2r(t_real_reso(spinTofphI->value())) * rads; + tof.angle_outplane_f = tl::d2r(t_real_reso(spinTofphF->value())) * rads; + + tof.sig_twotheta_i = tl::d2r(t_real_reso(spinTof2thISig->value())) * rads; + tof.sig_twotheta_f = tl::d2r(t_real_reso(spinTof2thFSig->value())) * rads; + tof.sig_outplane_i = tl::d2r(t_real_reso(spinTofphISig->value())) * rads; + tof.sig_outplane_f = tl::d2r(t_real_reso(spinTofphFSig->value())) * rads; + + tof.det_shape = radioTofDetSph->isChecked() ? TofDetShape::SPH : TofDetShape::CYL; + + + // Simple + simple.sig_ki = t_real_reso(spinSigKi->value()) / angs; + simple.sig_kf = t_real_reso(spinSigKf->value()) / angs; + simple.sig_ki_perp = t_real_reso(spinSigKi_perp->value()) / angs; + simple.sig_kf_perp = t_real_reso(spinSigKf_perp->value()) / angs; + simple.sig_ki_z = t_real_reso(spinSigKi_z->value()) / angs; + simple.sig_kf_z = t_real_reso(spinSigKf_z->value()) / angs; + + //tl::log_debug(m_tofparams.angle_ki_Q); + //tl::log_debug(m_tofparams.angle_kf_Q); + //tl::log_debug(m_tofparams.twotheta); + + // Calculation + switch(ResoDlg::GetSelectedAlgo()) + { + case ResoAlgo::CN: res = calc_cn(cn); break; + case ResoAlgo::POP: res = calc_pop(cn); break; + case ResoAlgo::ECK: res = calc_eck(cn); break; + case ResoAlgo::VIOL: res = calc_viol(tof); break; + case ResoAlgo::SIMPLE: res = calc_simplereso(simple); break; + default: tl::log_err("Unknown resolution algorithm selected."); return; + } + + editE->setText(tl::var_to_str(t_real_reso(cn.E/meV), g_iPrec).c_str()); + //if(m_pInstDlg) m_pInstDlg->SetParams(cn, res); + //if(m_pScatterDlg) m_pScatterDlg->SetParams(cn, res); + + if(res.bOk) + { + // -------------------------------------------------------------------------------- + // Vanadium width + struct Ellipse2d ellVa = + calc_res_ellipse(res.reso, res.reso_v, res.reso_s, + res.Q_avg, 0, 3, 1, 2, -1); + + //std::cout << ellVa.phi/M_PI*180. << std::endl; + t_real_reso dVanadiumFWHM_Q = ellVa.x_hwhm*2.; + t_real_reso dVanadiumFWHM_E = ellVa.y_hwhm*2.; + if(std::fabs(ellVa.phi) >= tl::get_pi()/4.) + { + dVanadiumFWHM_Q = ellVa.y_hwhm*2.; + dVanadiumFWHM_E = ellVa.x_hwhm*2.; + } + // -------------------------------------------------------------------------------- + + const std::string& strAA_1 = tl::get_spec_char_utf8("AA") + + tl::get_spec_char_utf8("sup-") + + tl::get_spec_char_utf8("sup1"); + const std::string& strAA_3 = tl::get_spec_char_utf8("AA") + + tl::get_spec_char_utf8("sup-") + + tl::get_spec_char_utf8("sup3"); + + std::ostringstream ostrRes; + + //ostrRes << std::scientific; + ostrRes.precision(g_iPrec); + ostrRes << "\n"; + + ostrRes << "

Correction Factors:\n"; + ostrRes << "\t

  • Resolution Volume: " << res.dResVol << " meV " << strAA_3 << "
  • \n"; + ostrRes << "\t
  • R0: " << res.dR0 << "

\n\n"; + + ostrRes << "

Bragg FWHMs:\n"; + ostrRes << "\t

  • Q_para: " << res.dBraggFWHMs[0] << " " << strAA_1 << "
  • \n"; + ostrRes << "\t
  • Q_ortho: " << res.dBraggFWHMs[1] << " " << strAA_1 << "
  • \n"; + ostrRes << "\t
  • Q_z: " << res.dBraggFWHMs[2] << " " << strAA_1 << "
  • \n"; + ostrRes << "\t
  • E: " << res.dBraggFWHMs[3] << " meV

\n\n"; + + ostrRes << "

Vanadium FWHM: " + << dVanadiumFWHM_Q << " " << strAA_1 << ", " + << dVanadiumFWHM_E << " meV

\n\n"; + + ostrRes << "

Resolution Matrix (Q_para, Q_ortho, Q_z, E):\n\n"; + ostrRes << "

\n"; + for(unsigned int i=0; i\n"; + for(unsigned int j=0; j" << std::setw(g_iPrec*2) << res.reso(i,j) << ""; + ostrRes << "\n"; + + if(i!=res.reso.size1()-1) + ostrRes << "\n"; + } + ostrRes << "

\n"; + + ostrRes << "

Resolution Vector: "; + for(std::size_t iVec=0; iVec\n"; + + ostrRes << "

Resolution Scalar: " << res.reso_s << "

\n"; + + ostrRes << ""; + + editResults->setHtml(QString::fromUtf8(ostrRes.str().c_str())); + labelStatus->setText("Calculation successful."); + +#ifndef NDEBUG + // check against ELASTIC approximation for perp. slope from Shirane p. 268 + // valid for small mosaicities + t_real_reso dEoverQperp = tl::co::hbar*tl::co::hbar*cn.ki / tl::co::m_n + * units::cos(cn.twotheta/2.) + * (1. + units::tan(units::abs(cn.twotheta/2.)) + * units::tan(units::abs(cn.twotheta/2.) - units::abs(cn.thetam))) + / meV / angs; + + tl::log_info("E/Q_perp (approximation for ki=kf) = ", dEoverQperp, " meV*A"); + tl::log_info("E/Q_perp (2nd approximation for ki=kf) = ", t_real_reso(4.*cn.ki * angs), " meV*A"); + + //std::cout << "thetas = " << m_tasparams.thetas/rads/M_PI*180. << std::endl; + //std::cout << "2thetam = " << 2.*m_tasparams.thetam/rads/M_PI*180. << std::endl; + //std::cout << "2thetaa = " << 2.*m_tasparams.thetaa/rads/M_PI*180. << std::endl; +#endif + + if(checkElli4dAutoCalc->isChecked()) + { + CalcElli4d(); + m_bEll4dCurrent = 1; + } + + if(groupSim->isChecked()) + RefreshSimCmd(); + + // calculate rlu quadric if a sample is defined + if(m_bHasUB) + { + // hkl crystal system: + // Qavg system in 1/A -> rotate back to orient system in 1/A -> + // transform to hkl rlu system + t_mat matQVec0 = tl::rotation_matrix_2d(-m_dAngleQVec0); + matQVec0.resize(4,4, true); + matQVec0(2,2) = matQVec0(3,3) = 1.; + matQVec0(2,0) = matQVec0(2,1) = matQVec0(2,3) = 0.; + matQVec0(3,0) = matQVec0(3,1) = matQVec0(3,2) = 0.; + matQVec0(0,2) = matQVec0(0,3) = 0.; + matQVec0(1,2) = matQVec0(1,3) = 0.; + const t_mat matQVec0inv = ublas::trans(matQVec0); + + const t_mat matUBinvQVec0 = ublas::prod(m_matUBinv, matQVec0); + const t_mat matQVec0invUB = ublas::prod(matQVec0inv, m_matUB); + // TODO: check: does this work for non-cubic crystals, i.e. non-orthogonal B matrices? + m_resoHKL = tl::transform(m_res.reso, matQVec0invUB, 1); + //m_resoHKL = ublas::prod(m_res.reso, matUBinvQVec0); + //m_resoHKL = ublas::prod(matQVec0invUB, m_resoHKL); + m_Q_avgHKL = ublas::prod(matUBinvQVec0, m_res.Q_avg); + + //std::cout << tl::r2d(m_dAngleQVec0) << std::endl; + //std::cout << m_Q_avgHKL << std::endl; + //std::cout << m_resoHKL << std::endl; + + + // system of scattering plane: (orient1, orient2, up) + // Qavg system in 1/A -> rotate back to orient system in 1/A -> + // transform to hkl rlu system -> rotate forward to orient system in rlu + const t_mat matToOrient = ublas::prod(m_matUrlu, matUBinvQVec0); + const t_mat matToOrientinv = ublas::prod(matQVec0invUB, m_matUinvrlu); + + // TODO: check: does this work for non-cubic crystals, i.e. non-orthogonal B matrices? + m_resoOrient = tl::transform(m_res.reso, matToOrientinv, 1); + //m_resoOrient = ublas::prod(m_res.reso, matToOrient); + //m_resoOrient = ublas::prod(matToOrientinv, m_resoOrient); + m_Q_avgOrient = ublas::prod(matToOrient, m_res.Q_avg); + //std::cout << m_Q_avgOrient << std::endl; + + if(m_res.reso_v.size() == 4) + { + m_reso_vHKL = ublas::prod(matUBinvQVec0, m_res.reso_v); + m_reso_vOrient = ublas::prod(matToOrient, m_res.reso_v); + } + } + + EmitResults(); + } + else + { + QString strErr = "Error: "; + strErr += res.strErr.c_str(); + labelStatus->setText(QString("") + strErr + QString("")); + } + } + catch(const std::exception& ex) + { + tl::log_err("Cannot calculate resolution: ", ex.what(), "."); + } +} + +void ResoDlg::RefreshSimCmd() +{ + const t_real_reso dMin = t_real_reso(tl::get_pi()/180./60.); + + std::ostringstream ostrCmd; + ostrCmd.precision(12); + + ostrCmd << "./templateTAS -n 1e6 verbose=1 "; + + ostrCmd << "KI=" << t_real_reso(m_tasparams.ki * angs) << " "; + ostrCmd << "KF=" << t_real_reso(m_tasparams.kf * angs) << " "; + ostrCmd << "QM=" << t_real_reso(m_tasparams.Q * angs) << " "; + ostrCmd << "EN=" << t_real_reso(m_tasparams.E / meV) << " "; + //ostrCmt << "FX=" << (m_tasparams.bki_fix ? "1" : "2") << " "; + + ostrCmd << "L1=" << t_real_reso(m_tasparams.dist_src_mono / meters) << " "; + ostrCmd << "L2=" << t_real_reso(m_tasparams.dist_mono_sample / meters) << " "; + ostrCmd << "L3=" << t_real_reso(m_tasparams.dist_sample_ana / meters) << " "; + ostrCmd << "L4=" << t_real_reso(m_tasparams.dist_ana_det / meters) << " "; + + ostrCmd << "SM=" << m_tasparams.dmono_sense << " "; + ostrCmd << "SS=" << m_tasparams.dsample_sense << " "; + ostrCmd << "SA=" << m_tasparams.dana_sense << " "; + + ostrCmd << "DM=" << t_real_reso(m_tasparams.mono_d / angs) << " "; + ostrCmd << "DA=" << t_real_reso(m_tasparams.ana_d / angs) << " "; + + ostrCmd << "RMV=" << t_real_reso(m_tasparams.mono_curvv / meters) << " "; + ostrCmd << "RMH=" << t_real_reso(m_tasparams.mono_curvh / meters) << " "; + ostrCmd << "RAV=" << t_real_reso(m_tasparams.ana_curvv / meters) << " "; + ostrCmd << "RAH=" << t_real_reso(m_tasparams.ana_curvh / meters) << " "; + + ostrCmd << "ETAM=" << t_real_reso(m_tasparams.mono_mosaic/rads/dMin) << " "; + ostrCmd << "ETAA=" << t_real_reso(m_tasparams.ana_mosaic/rads/dMin) << " "; + + ostrCmd << "ALF1=" << t_real_reso(m_tasparams.coll_h_pre_mono/rads/dMin) << " "; + ostrCmd << "ALF2=" << t_real_reso(m_tasparams.coll_h_pre_sample/rads/dMin) << " "; + ostrCmd << "ALF3=" << t_real_reso(m_tasparams.coll_h_post_sample/rads/dMin) << " "; + ostrCmd << "ALF4=" << t_real_reso(m_tasparams.coll_h_post_ana/rads/dMin) << " "; + ostrCmd << "BET1=" << t_real_reso(m_tasparams.coll_v_pre_mono/rads/dMin) << " "; + ostrCmd << "BET2=" << t_real_reso(m_tasparams.coll_v_pre_sample/rads/dMin) << " "; + ostrCmd << "BET3=" << t_real_reso(m_tasparams.coll_v_post_sample/rads/dMin) << " "; + ostrCmd << "BET4=" << t_real_reso(m_tasparams.coll_v_post_ana/rads/dMin) << " "; + + ostrCmd << "WM=" << t_real_reso(m_tasparams.mono_w / meters) << " "; + ostrCmd << "HM=" << t_real_reso(m_tasparams.mono_h / meters) << " "; + ostrCmd << "WA=" << t_real_reso(m_tasparams.ana_w / meters) << " "; + ostrCmd << "HA=" << t_real_reso(m_tasparams.ana_h / meters) << " "; + + ostrCmd << "NVM=" << m_tasparams.mono_numtiles_v << " "; + ostrCmd << "NHM=" << m_tasparams.mono_numtiles_h << " "; + ostrCmd << "NVA=" << m_tasparams.ana_numtiles_v << " "; + ostrCmd << "NHA=" << m_tasparams.ana_numtiles_h << " "; + + editSim->setPlainText(ostrCmd.str().c_str()); +} + +void ResoDlg::SetSelectedAlgo(ResoAlgo algo) +{ + for(int iItem=0; iItemcount(); ++iItem) + { + QVariant varAlgo = comboAlgo->itemData(iItem); + if(algo == static_cast(varAlgo.toInt())) + { + comboAlgo->setCurrentIndex(iItem); + //tl::log_debug("Set algo: ", iItem); + return; + } + } + + tl::log_err("Unknown resolution algorithm set."); +} + +ResoAlgo ResoDlg::GetSelectedAlgo() const +{ + ResoAlgo algoSel = ResoAlgo::UNKNOWN; + QVariant varAlgo = comboAlgo->itemData(comboAlgo->currentIndex()); + if(varAlgo == QVariant::Invalid) + tl::log_err("Unknown resolution algorithm selected."); + else + algoSel = static_cast(varAlgo.toInt()); + return algoSel; +} + +void ResoDlg::EmitResults() +{ + ResoAlgo algoSel = ResoDlg::GetSelectedAlgo(); + EllipseDlgParams params; + + params.reso = &m_res.reso; + params.reso_v = &m_res.reso_v; + params.reso_s = m_res.reso_s; + params.Q_avg = &m_res.Q_avg; + + params.resoHKL = &m_resoHKL; + params.reso_vHKL = &m_reso_vHKL; + params.Q_avgHKL = &m_Q_avgHKL; + + params.resoOrient = &m_resoOrient; + params.reso_vOrient = &m_reso_vOrient; + params.Q_avgOrient = &m_Q_avgOrient; + + params.algo = algoSel; + + emit ResoResultsSig(params); +} + +void ResoDlg::WriteLastConfig() +{ + if(!m_pSettings) + return; + + for(unsigned int iSpinBox=0; iSpinBoxsetValue(m_vecSpinNames[iSpinBox].c_str(), m_vecSpinBoxes[iSpinBox]->value()); + for(unsigned int iEditBox=0; iEditBoxsetValue(m_vecPosEditNames[iEditBox].c_str(), m_vecPosEditBoxes[iEditBox]->text().toDouble()); + for(unsigned int iRadio=0; iRadiosetValue(m_vecRadioNames[iRadio].c_str(), m_vecRadioPlus[iRadio]->isChecked()); + for(unsigned int iCheck=0; iChecksetValue(m_vecCheckNames[iCheck].c_str(), m_vecCheckBoxes[iCheck]->isChecked()); + for(unsigned int iCombo=0; iCombosetValue(m_vecComboNames[iCombo].c_str(), m_vecComboBoxes[iCombo]->currentIndex()); + + const int iAlgo = static_cast(ResoDlg::GetSelectedAlgo()); + m_pSettings->setValue("reso/algo", iAlgo); + + m_pSettings->setValue("reso/use_guide", groupGuide->isChecked()); +} + +void ResoDlg::ReadLastConfig() +{ + if(!m_pSettings) + return; + + bool bOldDontCalc = m_bDontCalc; + m_bDontCalc = 1; + + for(unsigned int iSpinBox=0; iSpinBoxcontains(m_vecSpinNames[iSpinBox].c_str())) + continue; + m_vecSpinBoxes[iSpinBox]->setValue(m_pSettings->value(m_vecSpinNames[iSpinBox].c_str()).value()); + } + + for(unsigned int iEditBox=0; iEditBoxcontains(m_vecPosEditNames[iEditBox].c_str())) + continue; + t_real_reso dEditVal = m_pSettings->value(m_vecPosEditNames[iEditBox].c_str()).value(); + m_vecPosEditBoxes[iEditBox]->setText(tl::var_to_str(dEditVal, g_iPrec).c_str()); + } + + for(unsigned int iCheckBox=0; iCheckBoxcontains(m_vecCheckNames[iCheckBox].c_str())) + continue; + m_vecCheckBoxes[iCheckBox]->setChecked(m_pSettings->value(m_vecCheckNames[iCheckBox].c_str()).value()); + } + + for(unsigned int iRadio=0; iRadiocontains(m_vecRadioNames[iRadio].c_str())) + continue; + + bool bChecked = m_pSettings->value(m_vecRadioNames[iRadio].c_str()).value(); + if(bChecked) + { + m_vecRadioPlus[iRadio]->setChecked(1); + //m_vecRadioMinus[iRadio]->setChecked(0);; + } + else + { + //m_vecRadioPlus[iRadio]->setChecked(0); + m_vecRadioMinus[iRadio]->setChecked(1);; + } + } + + for(unsigned int iCombo=0; iCombocontains(m_vecComboNames[iCombo].c_str())) + continue; + m_vecComboBoxes[iCombo]->setCurrentIndex( + m_pSettings->value(m_vecComboNames[iCombo].c_str()).value()); + } + + if(m_pSettings->contains("reso/algo")) + SetSelectedAlgo(static_cast(m_pSettings->value("reso/algo").value())); + + groupGuide->setChecked(m_pSettings->value("reso/use_guide").value()); + + m_bDontCalc = bOldDontCalc; + Calc(); +} + +void ResoDlg::Save(std::map& mapConf, const std::string& strXmlRoot) +{ + for(unsigned int iSpinBox=0; iSpinBoxvalue(); + + mapConf[strXmlRoot + m_vecSpinNames[iSpinBox]] = ostrVal.str(); + } + + for(unsigned int iEditBox=0; iEditBoxtext().toStdString(); + mapConf[strXmlRoot + m_vecPosEditNames[iEditBox]] = strVal; + } + + for(unsigned int iCheckBox=0; iCheckBoxisChecked() ? "1" : "0"); + + for(unsigned int iRadio=0; iRadioisChecked() ? "1" : "0"); + + for(unsigned int iCombo=0; iCombo(m_vecComboBoxes[iCombo]->currentIndex()); + + const int iAlgo = static_cast(ResoDlg::GetSelectedAlgo()); + mapConf[strXmlRoot + "reso/algo"] = tl::var_to_str(iAlgo); + + mapConf[strXmlRoot + "reso/use_guide"] = groupGuide->isChecked() ? "1" : "0"; +} + +void ResoDlg::Load(tl::Prop& xml, const std::string& strXmlRoot) +{ + bool bOldDontCalc = m_bDontCalc; + m_bDontCalc = 1; + + for(unsigned int iSpinBox=0; iSpinBox odSpinVal = xml.QueryOpt((strXmlRoot+m_vecSpinNames[iSpinBox]).c_str()); + if(odSpinVal) m_vecSpinBoxes[iSpinBox]->setValue(*odSpinVal); + } + + for(unsigned int iEditBox=0; iEditBox odEditVal = xml.QueryOpt((strXmlRoot+m_vecPosEditNames[iEditBox]).c_str()); + if(odEditVal) m_vecPosEditBoxes[iEditBox]->setText(tl::var_to_str(*odEditVal, g_iPrec).c_str()); + } + + for(unsigned int iCheck=0; iCheck obChecked = xml.QueryOpt((strXmlRoot+m_vecCheckNames[iCheck]).c_str()); + if(obChecked) m_vecCheckBoxes[iCheck]->setChecked(*obChecked); + } + + for(unsigned int iRadio=0; iRadio obChecked = xml.QueryOpt((strXmlRoot+m_vecRadioNames[iRadio]).c_str()); + if(obChecked) + { + if(*obChecked) + m_vecRadioPlus[iRadio]->setChecked(1); + else + m_vecRadioMinus[iRadio]->setChecked(1); + } + } + + for(unsigned int iCombo=0; iCombo oiComboIdx = xml.QueryOpt((strXmlRoot+m_vecComboNames[iCombo]).c_str()); + if(oiComboIdx) m_vecComboBoxes[iCombo]->setCurrentIndex(*oiComboIdx); + } + + boost::optional oiAlgo = xml.QueryOpt(strXmlRoot + "reso/algo"); + if(oiAlgo) SetSelectedAlgo(static_cast(*oiAlgo)); + + boost::optional obGroupVal = xml.QueryOpt((strXmlRoot+"reso/use_guide").c_str()); + if(obGroupVal) groupGuide->setChecked(*obGroupVal); + + m_bDontCalc = bOldDontCalc; + Calc(); +} + + +void ResoDlg::ResoParamsChanged(const ResoParams& params) +{ + //tl::log_debug("reso params changed"); + + bool bOldDontCalc = m_bDontCalc; + m_bDontCalc = 1; + + if(params.bSensesChanged[0]) params.bScatterSenses[0] ? radioMonoScatterPlus->setChecked(1) : radioMonoScatterMinus->setChecked(1); + if(params.bSensesChanged[1]) params.bScatterSenses[1] ? radioSampleScatterPlus->setChecked(1) : radioSampleScatterMinus->setChecked(1); + if(params.bSensesChanged[2]) params.bScatterSenses[2] ? radioAnaScatterPlus->setChecked(1) : radioAnaScatterMinus->setChecked(1); + + if(params.bMonoDChanged) spinMonod->setValue(params.dMonoD); + if(params.bAnaDChanged) spinAnad->setValue(params.dAnaD); + + m_bDontCalc = bOldDontCalc; + Calc(); +} + +void ResoDlg::RecipParamsChanged(const RecipParams& parms) +{ + //tl::log_debug("recip params changed"); + + bool bOldDontCalc = m_bDontCalc; + m_bDontCalc = 1; + + try + { + m_simpleparams.twotheta = m_tofparams.twotheta = m_tasparams.twotheta = + units::abs(t_real_reso(parms.d2Theta) * rads); + //std::cout << parms.dTheta/M_PI*180. << " " << parms.d2Theta/M_PI*180. << std::endl; + + m_simpleparams.ki = m_tofparams.ki = m_tasparams.ki = t_real_reso(parms.dki) / angs; + m_simpleparams.kf = m_tofparams.kf = m_tasparams.kf = t_real_reso(parms.dkf) / angs; + m_simpleparams.E = m_tofparams.E = m_tasparams.E = t_real_reso(parms.dE) * meV; + + //m_dAngleQVec0 = parms.dAngleQVec0; + //std::cout << "qvec0 in rlu: " << m_dAngleQVec0 << std::endl; + + t_vec vecHKL = -tl::make_vec({parms.Q_rlu[0], parms.Q_rlu[1], parms.Q_rlu[2]}); + t_real_reso dQ = parms.dQ; + + if(m_bHasUB) + { + if(m_matUB.size1() != vecHKL.size()) + vecHKL.resize(m_matUB.size1(), true); + t_vec vecQ = ublas::prod(m_matUB, vecHKL); + vecQ.resize(2,1); + m_dAngleQVec0 = -tl::vec_angle(vecQ); + dQ = ublas::norm_2(vecQ); + } + + m_simpleparams.Q = m_tofparams.Q = m_tasparams.Q = dQ / angs; + //std::cout << "qvec0 in 1/A: " << m_dAngleQVec0 << std::endl; + + + m_simpleparams.angle_ki_Q = m_tofparams.angle_ki_Q = m_tasparams.angle_ki_Q = + /*M_PI*rads -*/ tl::get_angle_ki_Q(m_tasparams.ki, m_tasparams.kf, m_tasparams.Q, 1); + m_simpleparams.angle_kf_Q = m_tofparams.angle_kf_Q = m_tasparams.angle_kf_Q = + /*M_PI*rads -*/ tl::get_angle_kf_Q(m_tasparams.ki, m_tasparams.kf, m_tasparams.Q, 1); + //m_tasparams.angle_ki_Q = units::abs(m_tasparams.angle_ki_Q); + //m_tasparams.angle_kf_Q = units::abs(m_tasparams.angle_kf_Q); + + /*std::cout << "ki = " << t_real_reso(m_tasparams.ki*angs) << std::endl; + std::cout << "kf = " << t_real_reso(m_tasparams.kf*angs) << std::endl; + std::cout << "Q = " << t_real_reso(m_tasparams.Q*angs) << std::endl; + + std::cout << "kiQ = " << t_real_reso(m_tasparams.angle_ki_Q/M_PI/rads * 180.) << std::endl; + std::cout << "kfQ = " << t_real_reso(m_tasparams.angle_kf_Q/M_PI/rads * 180.) << std::endl;*/ + + + editQ->setText(tl::var_to_str(dQ, g_iPrec).c_str()); + editE->setText(tl::var_to_str(parms.dE, g_iPrec).c_str()); + editKi->setText(tl::var_to_str(parms.dki, g_iPrec).c_str()); + editKf->setText(tl::var_to_str(parms.dkf, g_iPrec).c_str()); + } + catch(const std::exception& ex) + { + tl::log_err("Cannot set reciprocal parameters for resolution: ", ex.what(), "."); + } + + m_bDontCalc = bOldDontCalc; + if(m_bUpdateOnRecipEvent) + Calc(); +} + +void ResoDlg::RealParamsChanged(const RealParams& parms) +{ + //tl::log_debug("real params changed"); + + bool bOldDontCalc = m_bDontCalc; + m_bDontCalc = 1; + + m_tasparams.thetam = units::abs(t_real_reso(parms.dMonoT) * rads); + m_tasparams.thetaa = units::abs(t_real_reso(parms.dAnaT) * rads); + + m_tasparams.twotheta = t_real_reso(parms.dSampleTT) * rads; + m_tasparams.twotheta = units::abs(m_tasparams.twotheta); + m_simpleparams.twotheta = m_tofparams.twotheta = m_tasparams.twotheta; + + //std::cout << parms.dMonoT/M_PI*180. << ", " << parms.dAnaT/M_PI*180. << std::endl; + //std::cout << parms.dSampleTT/M_PI*180. << std::endl; + + m_bDontCalc = bOldDontCalc; + if(m_bUpdateOnRealEvent) + Calc(); +} + +void ResoDlg::SampleParamsChanged(const SampleParams& parms) +{ + try + { + //tl::log_debug("sample params changed"); + + tl::Lattice lattice(parms.dLattice[0],parms.dLattice[1],parms.dLattice[2], + parms.dAngles[0],parms.dAngles[1],parms.dAngles[2]); + + m_vecOrient1 = tl::make_vec({parms.dPlane1[0], parms.dPlane1[1], parms.dPlane1[2]}); + m_vecOrient2 = tl::make_vec({parms.dPlane2[0], parms.dPlane2[1], parms.dPlane2[2]}); + //m_vecOrient1 /= ublas::norm_2(m_vecOrient1); + //m_vecOrient2 /= ublas::norm_2(m_vecOrient2); + + m_matB = tl::get_B(lattice, 1); + m_matU = tl::get_U(m_vecOrient1, m_vecOrient2, &m_matB); + m_matUrlu = tl::get_U(m_vecOrient1, m_vecOrient2); + m_matUB = ublas::prod(m_matU, m_matB); + + bool bHasB = tl::inverse(m_matB, m_matBinv); + bool bHasU = tl::inverse(m_matU, m_matUinv); + bool bHasUrlu = tl::inverse(m_matUrlu, m_matUinvrlu); + m_matUBinv = ublas::prod(m_matBinv, m_matUinv); + + for(auto* pmat : {&m_matB, &m_matU, &m_matUB, &m_matUBinv, &m_matUrlu, &m_matUinvrlu}) + { + pmat->resize(4,4,1); + (*pmat)(3,0) = (*pmat)(3,1) = (*pmat)(3,2) = 0.; + (*pmat)(0,3) = (*pmat)(1,3) = (*pmat)(2,3) = 0.; + (*pmat)(3,3) = 1.; + } + + m_bHasUB = bHasB && bHasU && bHasUrlu; + } + catch(const std::exception& ex) + { + m_bHasUB = 0; + tl::log_err("Cannot set sample parameters for resolution: ", ex.what(), "."); + } +} + + +// -------------------------------------------------------------------------------- +// Monte-Carlo stuff + +void ResoDlg::checkAutoCalcElli4dChanged() +{ + if(checkElli4dAutoCalc->isChecked() && !m_bEll4dCurrent) + CalcElli4d(); +} + +void ResoDlg::CalcElli4d() +{ + m_ell4d = calc_res_ellipsoid4d( + m_res.reso, m_res.reso_v, m_res.reso_s, m_res.Q_avg); + + std::ostringstream ostrElli; + ostrElli << "\n"; + + ostrElli << "

Ellipsoid volume: " << m_ell4d.vol << "

\n\n"; + + ostrElli << "

Ellipsoid offsets:\n" + << "\t

  • Qx = " << m_ell4d.x_offs << "
  • \n" + << "\t
  • Qy = " << m_ell4d.y_offs << "
  • \n" + << "\t
  • Qz = " << m_ell4d.z_offs << "
  • \n" + << "\t
  • E = " << m_ell4d.w_offs << "

\n\n"; + + ostrElli << "

Ellipsoid HWHMs (unsorted):\n" + << "\t

  • " << m_ell4d.x_hwhm << "
  • \n" + << "\t
  • " << m_ell4d.y_hwhm << "
  • \n" + << "\t
  • " << m_ell4d.z_hwhm << "
  • \n" + << "\t
  • " << m_ell4d.w_hwhm << "

\n\n"; + + ostrElli << "\n"; + + editElli->setHtml(QString::fromUtf8(ostrElli.str().c_str())); +} + + +void ResoDlg::MCGenerate() +{ + if(!m_bEll4dCurrent) + CalcElli4d(); + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(m_pSettings && !m_pSettings->value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strLastDir = m_pSettings ? m_pSettings->value("reso/mc_dir", ".").toString() : "."; + QString _strFile = QFileDialog::getSaveFileName(this, "Save MC neutron data...", + strLastDir, "DAT files (*.dat);;All files (*.*)", nullptr, fileopt); + if(_strFile == "") + return; + + std::string strFile = _strFile.toStdString(); + + const int iNeutrons = spinMCNeutrons->value(); + const bool bCenter = checkMCCenter->isChecked(); + + std::ofstream ofstr(strFile); + if(!ofstr.is_open()) + { + QMessageBox::critical(this, "Error", "Cannot open file."); + return; + } + + std::vector vecNeutrons; + McNeutronOpts opts; + opts.bCenter = bCenter; + opts.coords = McNeutronCoords(comboMCCoords->currentIndex()); + opts.matU = m_matU; + opts.matB = m_matB; + opts.matUB = m_matUB; + opts.matUinv = m_matUinv; + opts.matBinv = m_matBinv; + opts.matUBinv = m_matUBinv; + + t_mat* pMats[] = {&opts.matU, &opts.matB, &opts.matUB, + &opts.matUinv, &opts.matBinv, &opts.matUBinv}; + + for(t_mat *pMat : pMats) + { + pMat->resize(4,4,1); + + for(int i0=0; i0<3; ++i0) + (*pMat)(i0,3) = (*pMat)(3,i0) = 0.; + (*pMat)(3,3) = 1.; + } + + + opts.dAngleQVec0 = m_dAngleQVec0; + vecNeutrons.resize(iNeutrons); + mc_neutrons(m_ell4d, iNeutrons, opts, vecNeutrons.begin()); + + + ofstr.precision(16); + + if(opts.coords == McNeutronCoords::DIRECT) + { + ofstr << "# coord_sys: direct\n"; + ofstr << "# columns: " << std::setw(13) << m_ell4d.x_lab + << std::setw(24) << m_ell4d.y_lab + << std::setw(24) << m_ell4d.z_lab + << std::setw(24) << m_ell4d.w_lab << "\n"; + } + else if(opts.coords == McNeutronCoords::ANGS) + { + ofstr << "# coord_sys: angstrom\n"; + ofstr << "# columns: " << std::setw(13) << "Qx (1/A)" + << std::setw(24) << "Qy (1/A)" + << std::setw(24) << "Qz (1/A)" + << std::setw(24) << "E (meV)" << "\n"; + } + else if(opts.coords == McNeutronCoords::RLU) + { + ofstr << "# coord_sys: rlu\n"; + ofstr << "# columns: " << std::setw(13) << "h (rlu)" + << std::setw(24) << "k (rlu)" + << std::setw(24) << "l (rlu)" + << std::setw(24) << "E (meV)" << "\n"; + } + else + { + ofstr << "# coord_sys: unknown\n"; + } + + + for(const t_vec& vecNeutron : vecNeutrons) + { + for(unsigned i=0; i<4; ++i) + ofstr << std::setw(24) << vecNeutron[i]; + ofstr << "\n"; + } + + if(m_pSettings) + m_pSettings->setValue("reso/mc_dir", QString(tl::get_dir(strFile).c_str())); +} + + +// -------------------------------------------------------------------------------- + + +void ResoDlg::AlgoChanged() +{ + std::string strAlgo = "\n"; + + switch(GetSelectedAlgo()) + { + case ResoAlgo::CN: + { + tabWidget->setTabEnabled(0,1); + tabWidget->setTabEnabled(1,0); + tabWidget->setTabEnabled(2,0); + tabWidget->setTabEnabled(3,0); + tabWidget->setTabEnabled(4,0); + strAlgo = "M. J. Cooper and
R. Nathans

\n"; + strAlgo += "" + "Acta Cryst. 23,
pp. 357-367

\n"; + strAlgo += "1967"; + break; + } + case ResoAlgo::POP: + { + tabWidget->setTabEnabled(0,1); + tabWidget->setTabEnabled(1,1); + tabWidget->setTabEnabled(2,0); + tabWidget->setTabEnabled(3,0); + tabWidget->setTabEnabled(4,0); + strAlgo = "M. Popovici
\n"; + strAlgo += "" + "Acta Cryst. A 31,
pp. 507-513

\n"; + strAlgo += "1975"; + break; + } + case ResoAlgo::ECK: + { + tabWidget->setTabEnabled(0,1); + tabWidget->setTabEnabled(1,1); + tabWidget->setTabEnabled(2,1); + tabWidget->setTabEnabled(3,0); + tabWidget->setTabEnabled(4,0); + strAlgo = "G. Eckold and
O. Sobolev

\n"; + strAlgo += "" + "NIM A 752,
pp. 54-64

\n"; + strAlgo += "2014"; + break; + } + case ResoAlgo::VIOL: + { + tabWidget->setTabEnabled(0,0); + tabWidget->setTabEnabled(1,0); + tabWidget->setTabEnabled(2,0); + tabWidget->setTabEnabled(3,1); + tabWidget->setTabEnabled(4,0); + strAlgo = "N. Violini et al.
\n"; + strAlgo += "" + "NIM A 736,
pp. 31-39

\n"; + strAlgo += "2014"; + break; + } + case ResoAlgo::SIMPLE: + { + tabWidget->setTabEnabled(0,0); + tabWidget->setTabEnabled(1,0); + tabWidget->setTabEnabled(2,0); + tabWidget->setTabEnabled(3,0); + tabWidget->setTabEnabled(4,1); + strAlgo = "Simple
\n"; + break; + } + default: + { + strAlgo += "unknown"; + break; + } + } + + strAlgo += "\n\n"; + labelAlgoRef->setText(strAlgo.c_str()); +} + + +// -------------------------------------------------------------------------------- + + +void ResoDlg::ButtonBoxClicked(QAbstractButton* pBtn) +{ + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::ApplyRole || + buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + WriteLastConfig(); + } + else if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::RejectRole) + { + reject(); + } + + if(buttonBox->buttonRole(pBtn) == QDialogButtonBox::AcceptRole) + { + QDialog::accept(); + } +} + +void ResoDlg::hideEvent(QHideEvent *event) +{ + if(m_pSettings) + m_pSettings->setValue("reso/wnd_geo", saveGeometry()); +} + +void ResoDlg::showEvent(QShowEvent *event) +{ + if(m_pSettings) + restoreGeometry(m_pSettings->value("reso/wnd_geo").toByteArray()); +} + +#include "ResoDlg.moc" diff --git a/tools/res/ResoDlg.h b/tools/res/ResoDlg.h new file mode 100644 index 0000000..c85e44b --- /dev/null +++ b/tools/res/ResoDlg.h @@ -0,0 +1,154 @@ +/* + * resolution calculation + * @author tweber + * @date 2013 - 2016 + * @license GPLv2 + */ + +#ifndef __RESO_DLG_H__ +#define __RESO_DLG_H__ + +#include +#include +#include + +#include +#include +#include + +#include "ui/ui_reso.h" +#include "cn.h" +#include "pop.h" +#include "eck.h" +#include "viol.h" +#include "simple.h" +#include "tlibs/math/linalg.h" +#include "tlibs/file/prop.h" +#ifndef NO_3D + #include "libs/plotgl.h" +#endif +#include "ellipse.h" +#include "dialogs/RecipParamDlg.h" +#include "dialogs/RealParamDlg.h" +#include "dialogs/EllipseDlg.h" + + +// parameters that are not already in RealParams or RecipParams +struct ResoParams +{ + bool bMonoDChanged = 0, bAnaDChanged = 0; + bool bSensesChanged[3] = {0,0,0}; + + t_real_reso dMonoD, dAnaD; + bool bScatterSenses[3]; +}; + +struct SampleParams +{ + t_real_reso dLattice[3]; + t_real_reso dAngles[3]; + t_real_reso dPlane1[3], dPlane2[3]; +}; + + +class ResoDlg : public QDialog, Ui::ResoDlg +{Q_OBJECT +protected: + std::vector m_vecSpinBoxes; + std::vector m_vecSpinNames; + + std::vector m_vecCheckBoxes; + std::vector m_vecCheckNames; + + std::vector m_vecPosEditBoxes; + std::vector m_vecPosEditNames; + + std::vector m_vecRadioPlus; + std::vector m_vecRadioMinus; + std::vector m_vecRadioNames; + + std::vector m_vecComboBoxes; + std::vector m_vecComboNames; + + void WriteLastConfig(); + void ReadLastConfig(); + + + // ------------------------------------------------------------------------- + ublas::vector m_vecOrient1, m_vecOrient2; + ublas::matrix m_matU, m_matB, m_matUinv, m_matBinv; + ublas::matrix m_matUrlu, m_matUinvrlu; + ublas::matrix m_matUB, m_matUBinv; + bool m_bHasUB = 0; + t_real_reso m_dAngleQVec0 = 0.; + // ------------------------------------------------------------------------- + + + EckParams m_tasparams; + ViolParams m_tofparams; + SimpleResoParams m_simpleparams; + + ResoResults m_res; + ublas::matrix m_resoHKL, m_resoOrient; + ublas::vector m_reso_vHKL, m_reso_vOrient; + ublas::vector m_Q_avgHKL, m_Q_avgOrient; + + bool m_bDontCalc; + bool m_bEll4dCurrent = 0; + Ellipsoid4d m_ell4d; + + QSettings* m_pSettings = 0; + bool m_bUpdateOnRealEvent = 1; + bool m_bUpdateOnRecipEvent = 1; + + ResoAlgo GetSelectedAlgo() const; + void SetSelectedAlgo(ResoAlgo algo); + +public: + ResoDlg(QWidget* pParent, QSettings* pSettings=0); + virtual ~ResoDlg(); + + void EmitResults(); + +protected slots: + void Calc(); + void AlgoChanged(); + + void SaveRes(); + void LoadRes(); + + void ButtonBoxClicked(QAbstractButton*); + void hideEvent (QHideEvent *event); + void showEvent(QShowEvent *event); + + void checkAutoCalcElli4dChanged(); + void CalcElli4d(); + void MCGenerate(); + + void RefreshQEPos(); + +protected: + void setupAlgos(); + void RefreshSimCmd(); + +public slots: + void ResoParamsChanged(const ResoParams& params); + void RecipParamsChanged(const RecipParams& parms); + void RealParamsChanged(const RealParams& parms); + void SampleParamsChanged(const SampleParams& parms); + +public: + void Load(tl::Prop& xml, const std::string& strXmlRoot); + void Save(std::map& mapConf, const std::string& strXmlRoot); + + void SetUpdateOn(bool bRealEvent, bool bRecipEvent) + { + m_bUpdateOnRealEvent = bRealEvent; + m_bUpdateOnRecipEvent = bRecipEvent; + } + +signals: + void ResoResultsSig(const EllipseDlgParams& params); +}; + +#endif diff --git a/tools/res/cn.cpp b/tools/res/cn.cpp new file mode 100644 index 0000000..0017a8a --- /dev/null +++ b/tools/res/cn.cpp @@ -0,0 +1,241 @@ +/** + * cooper-nathans calculation + * @author tweber + * @date 2013-2016 + * @license GPLv2 + * + * @desc This is a reimplementation in C++ of the file rc_cnmat.m of the + * rescal5 package by Zinkin, McMorrow, Tennant, Farhi, and Wildes: + * http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/ + * @desc see: [cn67] M. J. Cooper and R. Nathans, Acta Cryst. 23, 357 (1967), + * [ch73] N. J. Chesser and J. D. Axe, Acta Cryst. A 29, 160 (1973) + */ + +#include "cn.h" +#include "ellipse.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/geo.h" +#include "tlibs/math/math.h" +#include "tlibs/log/log.h" + +#include +#include + + +typedef t_real_reso t_real; +typedef ublas::matrix t_mat; +typedef ublas::vector t_vec; + +using angle = tl::t_angle_si; +using wavenumber = tl::t_wavenumber_si; +using energy = tl::t_energy_si; +using length = tl::t_length_si; + +static const auto angs = tl::get_one_angstrom(); +static const auto rads = tl::get_one_radian(); +static const auto meV = tl::get_one_meV(); +static const auto sec = tl::get_one_second(); +static const t_real pi = tl::get_pi(); +static const auto mn = tl::get_m_n(); +static const auto hbar = tl::get_hbar(); + + +// ----------------------------------------------------------------------------- +// R0 factor from formula (2) in [ch73] + +t_real R0_P(angle theta, angle coll, angle mosaic) +{ + t_real tS = units::sin(theta); + return std::sqrt(t_real(2)*pi) / rads * + tl::my_units_sqrt(t_real(1) / ( + t_real(1)/(coll*coll) + t_real(1)/(t_real(4)*mosaic*mosaic*tS*tS))); +} + +t_real R0_N(angle theta, angle mosaic, t_real refl) +{ + t_real tS = units::sin(theta); + return (refl / (t_real(2)*mosaic * tS)) / std::sqrt(t_real(2)*pi) * rads; +} + +t_real R0_J(wavenumber ki, wavenumber kf, angle twotheta) +{ + t_real tS = units::sin(twotheta); + return mn/hbar / (ki*ki * kf*kf*kf * tS) / angs/angs/angs/sec; +} + +t_real chess_R0(wavenumber ki, wavenumber kf, + angle theta_m, angle theta_a, angle twotheta_s, + angle mos_m, angle mos_a, angle coll_pre_mono_v, angle coll_post_ana_v, + t_real refl_m, t_real refl_a) +{ + return R0_J(ki, kf, twotheta_s) * + R0_P(theta_m, coll_pre_mono_v, mos_m) * R0_P(theta_a, coll_post_ana_v, mos_a) * + R0_N(theta_m, mos_m, refl_m) * R0_N(theta_a, mos_a, refl_a); +} +// ----------------------------------------------------------------------------- + + +ResoResults calc_cn(const CNParams& cn) +{ + ResoResults res; + + res.Q_avg.resize(4); + res.Q_avg[0] = cn.Q * angs; + res.Q_avg[1] = 0.; + res.Q_avg[2] = 0.; + res.Q_avg[3] = cn.E / meV; + + angle coll_h_pre_mono = cn.coll_h_pre_mono; + angle coll_v_pre_mono = cn.coll_v_pre_mono; + +/* + const length lam = tl::k2lam(cn.ki); + + if(cn.bGuide) + { + coll_h_pre_mono = lam*(cn.guide_div_h/angs); + coll_v_pre_mono = lam*(cn.guide_div_v/angs); + } +*/ + + // ------------------------------------------------------------------------- + // transformation matrix + + angle thetaa = cn.thetaa * cn.dana_sense; + angle thetam = cn.thetam * cn.dmono_sense; + angle ki_Q = cn.angle_ki_Q; + angle kf_Q = cn.angle_kf_Q; + + ki_Q *= cn.dsample_sense; + kf_Q *= cn.dsample_sense; + + + t_mat Ti = tl::rotation_matrix_2d(ki_Q/rads); + t_mat Tf = -tl::rotation_matrix_2d(kf_Q/rads); + + t_mat U = ublas::zero_matrix(6,6); + tl::submatrix_copy(U, Ti, 0, 0); + tl::submatrix_copy(U, Tf, 0, 3); + U(2,2) = 1.; U(2,5) = -1.; + U(3,0) = +t_real(2)*cn.ki * tl::get_KSQ2E() * angs; + U(3,3) = -t_real(2)*cn.kf * tl::get_KSQ2E() * angs; + U(4,0) = 1.; U(5,2) = 1.; + //tl::log_info("Trafo matrix (CN) = ", U); + + t_mat V(6,6); + if(!tl::inverse(U, V)) + { + res.bOk = false; + res.strErr = "Transformation matrix cannot be inverted."; + return res; + } + + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + // resolution matrix + + t_vec pm(2); + pm[0] = units::tan(thetam); + pm[1] = 1.; + pm /= cn.ki*angs * cn.mono_mosaic/rads; + + t_vec pa(2); + pa[0] = -units::tan(thetaa); + pa[1] = 1.; + pa /= cn.kf*angs * cn.ana_mosaic/rads; + + t_vec palf0(2); + palf0[0] = 2.*units::tan(thetam); + palf0[1] = 1.; + palf0 /= (cn.ki*angs * coll_h_pre_mono/rads); + + t_vec palf1(2); + palf1[0] = 0; + palf1[1] = 1.; + palf1 /= (cn.ki*angs * cn.coll_h_pre_sample/rads); + + t_vec palf2(2); + palf2[0] = -2.*units::tan(thetaa); + palf2[1] = 1.; + palf2 /= (cn.kf*angs * cn.coll_h_post_ana/rads); + + t_vec palf3(2); + palf3[0] = 0; + palf3[1] = 1.; + palf3 /= (cn.kf*angs * cn.coll_h_post_sample/rads); + + t_mat m01(2,2); + m01 = ublas::outer_prod(pm,pm) + + ublas::outer_prod(palf0,palf0) + + ublas::outer_prod(palf1,palf1); + t_mat m34(2,2); + m34 = ublas::outer_prod(pa,pa) + + ublas::outer_prod(palf2,palf2) + + ublas::outer_prod(palf3,palf3); + + t_mat M = ublas::zero_matrix(6,6); + tl::submatrix_copy(M, m01, 0, 0); + tl::submatrix_copy(M, m34, 3, 3); + + M(2,2) = t_real(1)/(cn.ki*cn.ki * angs*angs) * rads*rads * + ( + t_real(1)/(cn.coll_v_pre_sample*cn.coll_v_pre_sample) + + t_real(1)/((t_real(2)*units::sin(thetam)*cn.mono_mosaic)* + (t_real(2)*units::sin(thetam)*cn.mono_mosaic) + + coll_v_pre_mono*coll_v_pre_mono) + ); + M(5,5) = t_real(1)/(cn.kf*cn.kf * angs*angs) * rads*rads * + ( + t_real(1) / (cn.coll_v_post_sample*cn.coll_v_post_sample) + + t_real(1) / ((t_real(2)*units::sin(thetaa)*cn.ana_mosaic)* + (t_real(2)*units::sin(thetaa)*cn.ana_mosaic) + + cn.coll_v_post_ana*cn.coll_v_post_ana) + ); + // ------------------------------------------------------------------------- + + t_mat N = tl::transform(M, V, 1); + + N = ellipsoid_gauss_int(N, 5); + N = ellipsoid_gauss_int(N, 4); + + t_vec vec1 = tl::get_column(N, 1); + res.reso = N - ublas::outer_prod(vec1,vec1) + / (1./((cn.sample_mosaic/rads * cn.Q*angs) + * (cn.sample_mosaic/rads * cn.Q*angs)) + N(1,1)); + res.reso(2,2) = N(2,2); + res.reso *= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + + res.reso_v = ublas::zero_vector(4); + res.reso_s = 0.; + + if(cn.dsample_sense < 0.) + { + // mirror Q_perp + t_mat matMirror = tl::mirror_matrix(res.reso.size1(), 1); + res.reso = tl::transform(res.reso, matMirror, true); + res.reso_v[1] = -res.reso_v[1]; + } + + // ------------------------------------------------------------------------- + + + res.dResVol = tl::get_ellipsoid_volume(res.reso); + res.dR0 = chess_R0(cn.ki,cn.kf, thetam, thetaa, cn.twotheta, cn.mono_mosaic, + cn.ana_mosaic, cn.coll_v_pre_mono, cn.coll_v_post_ana, cn.dmono_refl, cn.dana_effic); + + // Bragg widths + for(unsigned int i=0; i<4; ++i) + res.dBraggFWHMs[i] = tl::SIGMA2FWHM/sqrt(res.reso(i,i)); + + if(tl::is_nan_or_inf(res.dR0) || tl::is_nan_or_inf(res.reso)) + { + res.strErr = "Invalid result."; + res.bOk = false; + return res; + } + + res.bOk = true; + return res; +} diff --git a/tools/res/cn.h b/tools/res/cn.h new file mode 100644 index 0000000..c588bdf --- /dev/null +++ b/tools/res/cn.h @@ -0,0 +1,69 @@ +/** + * cooper-nathans calculation + * @author tweber + * @date 2013-2016 + * @license GPLv2 + * + * @desc This is a reimplementation in C++ of the file rc_cnmat.m of the + * rescal5 package by Zinkin, McMorrow, Tennant, Farhi, and Wildes: + * http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/ + * @desc see: [cn67] M. J. Cooper and R. Nathans, Acta Cryst. 23, 357 (1967), + * [ch73] N. J. Chesser and J. D. Axe, Acta Cryst. A 29, 160 (1973) + */ + +#ifndef __TAKIN_CN_H__ +#define __TAKIN_CN_H__ + +#include "defs.h" +#include "tlibs/math/neutrons.h" + +namespace units = boost::units; +namespace codata = boost::units::si::constants::codata; + +struct CNParams +{ + // monochromator + tl::t_length_si mono_d; + tl::t_angle_si mono_mosaic; + t_real_reso dmono_sense = -1.; + + // analyser + tl::t_length_si ana_d; + tl::t_angle_si ana_mosaic; + t_real_reso dana_sense = -1.; + + // sample + tl::t_angle_si sample_mosaic; + tl::t_length_si sample_lattice[3]; + tl::t_angle_si sample_angles[3]; + t_real_reso dsample_sense = 1.; + + // collimators + tl::t_angle_si coll_h_pre_mono; + tl::t_angle_si coll_h_pre_sample; + tl::t_angle_si coll_h_post_sample; + tl::t_angle_si coll_h_post_ana; + tl::t_angle_si coll_v_pre_mono; + tl::t_angle_si coll_v_pre_sample; + tl::t_angle_si coll_v_post_sample; + tl::t_angle_si coll_v_post_ana; + + tl::t_wavenumber_si ki, kf, Q; + tl::t_energy_si E; + + tl::t_angle_si thetaa, thetam; + tl::t_angle_si twotheta; + + tl::t_angle_si angle_ki_Q; + tl::t_angle_si angle_kf_Q; + + // resolution volume stuff + t_real_reso dmono_refl; + t_real_reso dana_effic; + + bool bCalcR0 = 1; +}; + +extern ResoResults calc_cn(const CNParams& cn); + +#endif diff --git a/tools/res/defs.h b/tools/res/defs.h new file mode 100644 index 0000000..def8f31 --- /dev/null +++ b/tools/res/defs.h @@ -0,0 +1,42 @@ +/* + * type definitions for reso + * @author tweber + * @date mar-2016 + * @license GPLv2 + */ + +#ifndef __RESO_DEFS_H__ +#define __RESO_DEFS_H__ + +#include "libs/globals.h" + + +#include +#include +#include + +namespace ublas = boost::numeric::ublas; + +using t_real_reso = ::t_real_glob; + +struct ResoResults +{ + bool bOk; + std::string strErr; + + ublas::matrix reso; // quadratic part of quadric + ublas::vector reso_v; // linear part of quadric + t_real_reso reso_s; // constant part of quadric + + ublas::vector Q_avg; + t_real_reso dR0; // resolution prefactor + t_real_reso dResVol; // resolution volume in 1/A^3 * meV + + t_real_reso dBraggFWHMs[4]; +}; + + +// all algos +enum class ResoAlgo { CN=1, POP=2, ECK=3, VIOL=4, SIMPLE=100, UNKNOWN=-1 }; + +#endif diff --git a/tools/res/eck.cpp b/tools/res/eck.cpp new file mode 100644 index 0000000..36b198f --- /dev/null +++ b/tools/res/eck.cpp @@ -0,0 +1,441 @@ +/* + * implementation of the eckold-sobolev algo + * + * @author tweber + * @date feb-2015 + * @license GPLv2 + * + * @desc for algorithm: [eck14] G. Eckold and O. Sobolev, NIM A 752, pp. 54-64 (2014) + */ + +#include "eck.h" + +#include "tlibs/math/linalg.h" +#include "tlibs/math/math.h" +#include "ellipse.h" + +#include +#include +#include +#include + + +typedef t_real_reso t_real; +typedef ublas::matrix t_mat; +typedef ublas::vector t_vec; + +using angle = tl::t_angle_si; +using wavenumber = tl::t_wavenumber_si; +using energy = tl::t_energy_si; +using length = tl::t_length_si; +using inv_length = tl::t_length_inverse_si; + +static const auto angs = tl::get_one_angstrom(); +static const auto rads = tl::get_one_radian(); +static const auto meV = tl::get_one_meV(); +static const auto cm = tl::get_one_centimeter(); +static const auto secs = tl::get_one_second(); + + +static std::tuple +get_mono_vals(const length& src_w, const length& src_h, + const length& mono_w, const length& mono_h, + const length& dist_src_mono, const length& dist_mono_sample, + const wavenumber& ki, const angle& thetam, + const angle& coll_h_pre_mono, const angle& coll_h_pre_sample, + const angle& coll_v_pre_mono, const angle& coll_v_pre_sample, + const angle& mono_mosaic, const angle& mono_mosaic_v, + const inv_length& inv_mono_curvh, const inv_length& inv_mono_curvv, + const length& pos_x , const length& pos_y, const length& pos_z, + t_real dRefl) +{ + // A matrix: formula 26 in [eck14] + t_mat A = ublas::identity_matrix(3); + { + const auto A_t0 = t_real(1) / mono_mosaic; + const auto A_tx = inv_mono_curvh*dist_mono_sample / units::abs(units::sin(thetam)); + const auto A_t1 = A_t0*A_tx; + + A(0,0) = t_real(4)*std::log(t_real(2))/(ki*angs*ki*angs) * + units::tan(thetam)*units::tan(thetam) * + ( +/*a*/ + units::pow<2>(t_real(2)/coll_h_pre_mono) *rads*rads +/*b*/ + units::pow<2>(t_real(2)*dist_src_mono/src_w) +/*c*/ + A_t0*A_t0 *rads*rads + ); + A(0,1) = A(1,0) = t_real(4)*std::log(t_real(2))/(ki*angs*ki*angs) * + units::tan(thetam) * + ( +/*w*/ + t_real(2)*tl::my_units_pow2(t_real(1)/coll_h_pre_mono) *rads*rads +/*x*/ + t_real(2)*dist_src_mono*(dist_src_mono-dist_mono_sample)/(src_w*src_w) +/*y*/ + A_t0*A_t0 * rads*rads +/*z*/ - A_t0*A_t1 *rads*rads + ); + A(1,1) = 4.*std::log(2.)/(ki*angs*ki*angs) * + ( +/*1*/ + units::pow<2>(t_real(1)/coll_h_pre_mono) *rads*rads +/*2*/ + units::pow<2>(t_real(1)/coll_h_pre_sample) *rads*rads +/*3*/ + units::pow<2>((dist_src_mono-dist_mono_sample)/src_w) +/*4*/ + units::pow<2>(dist_mono_sample/(mono_w*units::abs(units::sin(thetam)))) + +/*5*/ + A_t0*A_t0 *rads*rads +/*6*/ - t_real(2)*A_t0*A_t1 *rads*rads +/*7*/ + A_t1*A_t1 *rads*rads + ); + } + + // Av matrix: formula 38 in [eck14] + // some typos in paper leading to the (false) result of a better Qz resolution when focusing + // => trying to match terms in Av with corresponding terms in A + // corresponding pre-mono terms commented out in Av, as they are not considered there + t_mat Av(2,2); + { + const auto Av_t0 = t_real(0.5) / (mono_mosaic_v*units::abs(units::sin(thetam))); + const auto Av_t1 = inv_mono_curvv*dist_mono_sample / mono_mosaic_v; + + Av(0,0) = t_real(4)*std::log(t_real(2))/(ki*angs*ki*angs) * + ( +/*1*/ // + units::pow<2>(t_real(1)/coll_v_pre_mono) *rads*rads // missing in paper? +/*2*/ + units::pow<2>(t_real(1)/coll_v_pre_sample) *rads*rads +/*~3*/ + units::pow<2>(dist_mono_sample/src_h) +/*4*/ + units::pow<2>(dist_mono_sample/mono_h) + +/*5*/ + Av_t0*Av_t0 * rads*rads // typo in paper? +/*6*/ - t_real(2)*Av_t0*Av_t1 * rads*rads +/*7*/ + Av_t1*Av_t1 * rads*rads // missing in paper? + ); + Av(0,1) = Av(1,0) = t_real(4)*std::log(t_real(2))/(ki*angs*ki*angs) * + ( +/*w*/ // - units::pow<2>(1./coll_v_pre_mono) *rads*rads // missing in paper? +/*~x*/ + dist_src_mono*dist_mono_sample/(src_h*src_h) +/*y*/ - Av_t0*Av_t0 * rads*rads +/*z*/ + Av_t0*Av_t1 * rads*rads + ); + Av(1,1) = t_real(4)*std::log(t_real(2))/(ki*angs*ki*angs) * + ( +/*a*/ + units::pow<2>(t_real(1)/(coll_v_pre_mono)) *rads*rads +/*b*/ + units::pow<2>(dist_src_mono/src_h) +/*c*/ + Av_t0*Av_t0 *rads*rads + ); + } + + // B vector: formula 27 in [eck14] + t_vec B(3); + { + const auto B_t0 = inv_mono_curvh / (mono_mosaic*mono_mosaic*units::abs(units::sin(thetam))); + + B(0) = t_real(8)*std::log(t_real(2))*pos_y / (ki*angs) * units::tan(thetam) * + ( +/*i*/ + t_real(2)*dist_src_mono / (src_w*src_w) +/*j*/ + B_t0 *rads*rads + ); + B(1) = t_real(8)*std::log(t_real(2))*pos_y / (ki*angs) * + ( +/*r*/ - dist_mono_sample / (units::pow<2>(mono_w*units::abs(units::sin(thetam)))) +/*s*/ + B_t0 * rads*rads +/*t*/ - B_t0 * rads*rads * inv_mono_curvh*dist_mono_sample / + (units::abs(units::sin(thetam))) +/*u*/ + (dist_src_mono-dist_mono_sample) / (src_w*src_w) + ); + } + + // Bv vector: formula 39 in [eck14] + t_vec Bv(2); + { + const auto Bv_t0 = inv_mono_curvv/(mono_mosaic_v*mono_mosaic_v); + + Bv(0) = t_real(8)*std::log(t_real(2))*pos_z / (ki*angs) * t_real(-1.) * + ( +/*r*/ + dist_mono_sample / (mono_h*mono_h) // typo in paper? +/*~s*/ - t_real(0.5)*Bv_t0 *rads*rads / units::abs(units::sin(thetam)) +/*~t*/ + Bv_t0 * rads*rads * inv_mono_curvv*dist_mono_sample +/*~u*/ + dist_mono_sample / (src_h*src_h) // typo in paper? + ); + Bv(1) = t_real(8)*std::log(t_real(2))*pos_z / (ki*angs) * t_real(-1.) * + ( +/*i*/ + dist_src_mono / (src_h*src_h) // typo in paper? +/*j*/ - t_real(0.5)*Bv_t0/units::abs(units::sin(thetam)) * rads*rads + ); + } + + + // C scalar: formula 28 in [eck14] + t_real C = t_real(4)*std::log(t_real(2))*pos_y*pos_y * + ( + t_real(1)/(src_w*src_w) + + units::pow<2>(t_real(1)/(mono_w*units::abs(units::sin(thetam)))) + + units::pow<2>(inv_mono_curvh/(mono_mosaic * units::abs(units::sin(thetam)))) *rads*rads + ); + + // Cv scalar: formula 40 in [eck14] + t_real Cv = t_real(4)*std::log(t_real(2))*pos_z*pos_z * + ( + t_real(1)/(src_h*src_h) + + t_real(1)/(mono_h*mono_h) + + units::pow<2>(inv_mono_curvv/mono_mosaic_v) *rads*rads + ); + + + // z components, [eck14], equ. 42 + A(2,2) = Av(0,0) - Av(0,1)*Av(0,1)/Av(1,1); + B[2] = Bv[0] - Bv[1]*Av(0,1)/Av(1,1); + t_real D = Cv - t_real(0.25)*Bv[1]/Av(1,1); + + + // [eck14], equ. 54 + t_real refl = dRefl * std::sqrt(tl::get_pi()/Av(1,1)); + + + return std::make_tuple(A, B, C, D, refl); +} + + +ResoResults calc_eck(const EckParams& eck) +{ + angle twotheta = eck.twotheta * eck.dsample_sense; + angle thetaa = eck.thetaa * eck.dana_sense; + angle thetam = eck.thetam * eck.dmono_sense; + angle ki_Q = eck.angle_ki_Q * eck.dsample_sense; + angle kf_Q = eck.angle_kf_Q * eck.dsample_sense; + //kf_Q = ki_Q + twotheta; + + + // -------------------------------------------------------------------- + // mono/ana focus + length mono_curvh = eck.mono_curvh, mono_curvv = eck.mono_curvv; + length ana_curvh = eck.ana_curvh, ana_curvv = eck.ana_curvv; + + if(eck.bMonoIsOptimallyCurvedH) mono_curvh = tl::foc_curv(eck.dist_src_mono, eck.dist_mono_sample, units::abs(t_real(2)*thetam), false); + if(eck.bMonoIsOptimallyCurvedV) mono_curvv = tl::foc_curv(eck.dist_src_mono, eck.dist_mono_sample, units::abs(t_real(2)*thetam), true); + if(eck.bAnaIsOptimallyCurvedH) ana_curvh = tl::foc_curv(eck.dist_sample_ana, eck.dist_ana_det, units::abs(t_real(2)*thetaa), false); + if(eck.bAnaIsOptimallyCurvedV) ana_curvv = tl::foc_curv(eck.dist_sample_ana, eck.dist_ana_det, units::abs(t_real(2)*thetaa), true); + + //mono_curvh *= eck.dmono_sense; mono_curvv *= eck.dmono_sense; + //ana_curvh *= eck.dana_sense; ana_curvv *= eck.dana_sense; + + inv_length inv_mono_curvh = t_real(0)/cm, inv_mono_curvv = t_real(0)/cm; + inv_length inv_ana_curvh = t_real(0)/cm, inv_ana_curvv = t_real(0)/cm; + + if(eck.bMonoIsCurvedH) inv_mono_curvh = t_real(1)/mono_curvh; + if(eck.bMonoIsCurvedV) inv_mono_curvv = t_real(1)/mono_curvv; + if(eck.bAnaIsCurvedH) inv_ana_curvh = t_real(1)/ana_curvh; + if(eck.bAnaIsCurvedV) inv_ana_curvv = t_real(1)/ana_curvv; + + //if(eck.bMonoIsCurvedH) tl::log_debug("mono curv h: ", mono_curvh); + //if(eck.bMonoIsCurvedV) tl::log_debug("mono curv v: ", mono_curvv); + //if(eck.bAnaIsCurvedH) tl::log_debug("ana curv h: ", ana_curvh); + //if(eck.bAnaIsCurvedV) tl::log_debug("ana curv v: ", ana_curvv); + // -------------------------------------------------------------------- + + + const length lam = tl::k2lam(eck.ki); + + angle coll_h_pre_mono = eck.coll_h_pre_mono; + angle coll_v_pre_mono = eck.coll_v_pre_mono; + + if(eck.bGuide) + { + coll_h_pre_mono = lam*(eck.guide_div_h/angs); + coll_v_pre_mono = lam*(eck.guide_div_v/angs); + } + + + //std::cout << "thetaM = " << t_real(thetam/rads/M_PI*180.) << " deg"<< std::endl; + //std::cout << "thetaA = " << t_real(thetaa/rads/M_PI*180.) << " deg"<< std::endl; + + //std::cout << "ki = " << t_real(eck.ki*angs) << ", kf = " << t_real(eck.kf*angs) << std::endl; + //std::cout << "Q = " << t_real(eck.Q*angs) << ", E = " << t_real(eck.E/meV) << std::endl; + + //std::cout << "kiQ = " << t_real(ki_Q/rads/M_PI*180.) << " deg"<< std::endl; + //std::cout << "kfQ = " << t_real(kf_Q/rads/M_PI*180.) << " deg"<< std::endl; + //std::cout << "2theta = " << t_real(twotheta/rads/M_PI*180.) << " deg"<< std::endl; + + + ResoResults res; + + res.Q_avg.resize(4); + res.Q_avg[0] = eck.Q*angs; + res.Q_avg[1] = 0.; + res.Q_avg[2] = 0.; + res.Q_avg[3] = eck.E/meV; + + + //-------------------------------------------------------------------------- + // mono part + + std::launch lpol = /*std::launch::deferred |*/ std::launch::async; + std::future> futMono + = std::async(lpol, get_mono_vals, + eck.src_w, eck.src_h, + eck.mono_w, eck.mono_h, + eck.dist_src_mono, eck.dist_mono_sample, + eck.ki, thetam, + coll_h_pre_mono, eck.coll_h_pre_sample, + coll_v_pre_mono, eck.coll_v_pre_sample, + eck.mono_mosaic, eck.mono_mosaic_v, + inv_mono_curvh, inv_mono_curvv, + eck.pos_x , eck.pos_y, eck.pos_z, + eck.dmono_refl); + + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- + // ana part + + // equ 43 in [eck14] + length pos_y2 = - eck.pos_x*units::sin(twotheta) + + eck.pos_y*units::cos(twotheta); + std::future> futAna + = std::async(lpol, get_mono_vals, + eck.det_w, eck.det_h, + eck.ana_w, eck.ana_h, + eck.dist_ana_det, eck.dist_sample_ana, + eck.kf, -thetaa, + eck.coll_h_post_ana, eck.coll_h_post_sample, + eck.coll_v_post_ana, eck.coll_v_post_sample, + eck.ana_mosaic, eck.ana_mosaic_v, + inv_ana_curvh, inv_ana_curvv, + eck.pos_x, pos_y2, eck.pos_z, + eck.dana_effic); + + //-------------------------------------------------------------------------- + // get mono & ana results + + std::tuple tupMono = futMono.get(); + const t_mat& A = std::get<0>(tupMono); + const t_vec& B = std::get<1>(tupMono); + const t_real& C = std::get<2>(tupMono); + const t_real& D = std::get<3>(tupMono); + const t_real& dReflM = std::get<4>(tupMono); + + std::tuple tupAna = futAna.get(); + const t_mat& E = std::get<0>(tupAna); + const t_vec& F = std::get<1>(tupAna); + const t_real& G = std::get<2>(tupAna); + const t_real& H = std::get<3>(tupAna); + const t_real& dReflA = std::get<4>(tupAna); + + /*std::cout << "A = " << A << std::endl; + std::cout << "B = " << B << std::endl; + std::cout << "C = " << C << std::endl; + std::cout << "D = " << D << std::endl; + std::cout << "RM = " << dReflM << std::endl; + + std::cout << "E = " << E << std::endl; + std::cout << "F = " << F << std::endl; + std::cout << "G = " << G << std::endl; + std::cout << "H = " << H << std::endl; + std::cout << "RA = " << dReflA << std::endl;*/ + + //-------------------------------------------------------------------------- + + + // equ 4 & equ 53 in [eck14] + const t_real dE = (eck.ki*eck.ki - eck.kf*eck.kf) / (t_real(2)*eck.Q*eck.Q); + const wavenumber kipara = eck.Q*(t_real(0.5)+dE); + const wavenumber kfpara = eck.Q-kipara; + wavenumber kperp = tl::my_units_sqrt(units::abs(kipara*kipara - eck.ki*eck.ki)); + kperp *= eck.dsample_sense; + + const t_real ksq2E = tl::get_KSQ2E(); + + // trafo, equ 52 in [eck14] + t_mat T = ublas::identity_matrix(6); + T(0,3) = T(1,4) = T(2,5) = -1.; + T(3,0) = t_real(2)*ksq2E * kipara * angs; + T(3,3) = t_real(2)*ksq2E * kfpara * angs; + T(3,1) = t_real(2)*ksq2E * kperp * angs; + T(3,4) = t_real(-2)*ksq2E * kperp * angs; + T(4,1) = T(5,2) = (0.5 - dE); + T(4,4) = T(5,5) = (0.5 + dE); + t_mat Tinv; + if(!tl::inverse(T, Tinv)) + { + res.bOk = false; + res.strErr = "Matrix T cannot be inverted."; + return res; + } + //std::cout << "Trafo matrix (Eck) = " << T << std::endl; + //std::cout << "Tinv = " << Tinv << std::endl; + + // equ 54 in [eck14] + t_mat Dalph_i = tl::rotation_matrix_3d_z(-ki_Q/rads); + t_mat Dalph_f = tl::rotation_matrix_3d_z(-kf_Q/rads); + t_mat Arot = tl::transform(A, Dalph_i, 1); + t_mat Erot = tl::transform(E, Dalph_f, 1); + + t_mat matAE = ublas::zero_matrix(6,6); + tl::submatrix_copy(matAE, Arot, 0,0); + tl::submatrix_copy(matAE, Erot, 3,3); + //std::cout << "AE = " << matAE << std::endl; + + // U1 matrix + t_mat U1 = tl::transform(matAE, Tinv, 1); // typo in paper in quadric trafo in equ 54 (top)? + //std::cout << "U1 = " << U1 << std::endl; + + // V1 vector + t_vec vecBF = ublas::zero_vector(6); + t_vec vecBrot = ublas::prod(ublas::trans(Dalph_i), B); + t_vec vecFrot = ublas::prod(ublas::trans(Dalph_f), F); + tl::subvector_copy(vecBF, vecBrot, 0); + tl::subvector_copy(vecBF, vecFrot, 3); + t_vec V1 = ublas::prod(vecBF, Tinv); + + + + //-------------------------------------------------------------------------- + // integrate last 2 vars -> equs 57 & 58 in [eck14] + + t_mat U2 = ellipsoid_gauss_int(U1, 5); + t_mat U = ellipsoid_gauss_int(U2, 4); + + t_vec V2 = ellipsoid_gauss_int(V1, U1, 5); + t_vec V = ellipsoid_gauss_int(V2, U2, 4); + + t_real W = (C + D + G + H) - 0.25*V1[5]/U1(5,5) - 0.25*V2[4]/U2(4,4); + + t_real Z = dReflM*dReflA + * std::sqrt(tl::get_pi()/std::abs(U1(5,5))) + * std::sqrt(tl::get_pi()/std::abs(U2(4,4))); + + /*std::cout << "U = " << U << std::endl; + std::cout << "V = " << V << std::endl; + std::cout << "W = " << W << std::endl; + std::cout << "Z = " << Z << std::endl;*/ + //-------------------------------------------------------------------------- + + + // quadratic part of quadric (matrix U) + // careful: factor -0.5*... missing in U matrix compared to normal gaussian! + res.reso = 2. * U /** tl::SIGMA2FWHM*tl::SIGMA2FWHM*/; + // linear (vector V) and constant (scalar W) part of quadric + res.reso_v = V; + res.reso_s = W; + + if(eck.dsample_sense < 0.) + { + // mirror Q_perp + t_mat matMirror = tl::mirror_matrix(res.reso.size1(), 1); + res.reso = tl::transform(res.reso, matMirror, true); + res.reso_v[1] = -res.reso_v[1]; + } + + // prefactor and volume + res.dResVol = tl::get_ellipsoid_volume(res.reso); + res.dR0 = Z /** res.dResVol*/; // TODO: check + + // Bragg widths + for(unsigned int i=0; i<4; ++i) + res.dBraggFWHMs[i] = tl::SIGMA2FWHM/sqrt(res.reso(i,i)); + + if(tl::is_nan_or_inf(res.dR0) || tl::is_nan_or_inf(res.reso)) + { + res.strErr = "Invalid result."; + res.bOk = false; + return res; + } + + res.bOk = true; + return res; +} diff --git a/tools/res/eck.h b/tools/res/eck.h new file mode 100644 index 0000000..10415bc --- /dev/null +++ b/tools/res/eck.h @@ -0,0 +1,28 @@ +/* + * implementation of the eckold-sobolev algo + * + * @author tweber + * @date feb-2015 + * @license GPLv2 + * + * @desc for algorithm: [eck14] G. Eckold and O. Sobolev, NIM A 752, pp. 54-64 (2014) + */ + +#ifndef __TAKIN_ECK_H__ +#define __TAKIN_ECK_H__ + +#include "pop.h" + +struct EckParams : public PopParams +{ + tl::t_angle_si mono_mosaic_v; + tl::t_angle_si ana_mosaic_v; + + tl::t_length_si pos_x, pos_y, pos_z; +}; + + +extern ResoResults calc_eck(const EckParams& eck); + + +#endif diff --git a/tools/res/ellipse.h b/tools/res/ellipse.h new file mode 100644 index 0000000..c08de1d --- /dev/null +++ b/tools/res/ellipse.h @@ -0,0 +1,527 @@ +/** + * resolution ellipse calculation + * @author tweber + * @date 14-may-2013 + * @license GPLv2 + * + * @desc This is a reimplementation in C++ of the file rc_projs.m of the + * rescal5 package by Zinkin, McMorrow, Tennant, Farhi, and Wildes: + * http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/ + */ + +#ifndef __RES_ELLIPSE__ +#define __RES_ELLIPSE__ + +#include +#include +#include +#include + +#include +#include +namespace ublas = boost::numeric::ublas; + +#include "tlibs/math/linalg.h" +#include "tlibs/math/linalg2.h" +#include "tlibs/math/geo.h" +#include "tlibs/math/quat.h" +#include "tlibs/math/math.h" +#include "defs.h" + + +template +struct Ellipse2d +{ + tl::QuadEllipsoid quad; + + t_real phi, slope; + t_real x_hwhm, y_hwhm; + t_real x_offs, y_offs; + t_real area; + + std::string x_lab, y_lab; + + ublas::vector operator()(t_real t) const; + void GetCurvePoints(std::vector& x, std::vector& y, + std::size_t iPoints=512, t_real *pLRTB=0); +}; + +template +struct Ellipsoid3d +{ + tl::QuadEllipsoid quad; + ublas::matrix rot; + + t_real x_hwhm, y_hwhm, z_hwhm; + t_real x_offs, y_offs, z_offs; + t_real vol; + + std::string x_lab, y_lab, z_lab; +}; + +template +struct Ellipsoid4d +{ + tl::QuadEllipsoid quad; + ublas::matrix rot; + + t_real x_hwhm, y_hwhm, z_hwhm, w_hwhm; + t_real x_offs, y_offs, z_offs, w_offs; + t_real vol; + + std::string x_lab, y_lab, z_lab, w_lab; +}; + + +enum class EllipseCoordSys : int +{ + AUTO = -1, + + Q_AVG = 0, // Q|| Qperp system (1/A) + RLU, // absolute hkl system (rlu) + RLU_ORIENT // system using scattering plane (rlu) +}; + + + +// -------------------------------------------------------------------------------- + + +/* + * this is a 1:1 C++ reimplementation of 'rc_int' from 'mcresplot' and 'rescal5' + * (see also [eck14], equ. 57) + * integrate over row/column iIdx + */ +template +ublas::matrix ellipsoid_gauss_int(const ublas::matrix& mat, std::size_t iIdx) +{ + ublas::vector b(mat.size1()); + for(std::size_t i=0; i bb = ublas::outer_prod(b,b); + + ublas::matrix m = tl::remove_elems(mat, iIdx); + m -= bb / mat(iIdx, iIdx); + + return m; +} + +/* + * (see [eck14], equ. 57) + */ +template +ublas::vector ellipsoid_gauss_int(const ublas::vector& vec, + const ublas::matrix& mat, std::size_t iIdx) +{ + ublas::vector b(mat.size1()); + for(std::size_t i=0; i vecInt = tl::remove_elem(vec, iIdx); + vecInt -= b*vec[iIdx] / mat(iIdx, iIdx); + + return vecInt; +} + + +// -------------------------------------------------------------------------------- + +template +std::ostream& operator<<(std::ostream& ostr, const Ellipse2d& ell) +{ + ostr << "phi = " << tl::r2d(ell.phi) << " deg \n"; + ostr << "slope = " << ell.slope << " deg \n"; + ostr << "x_hwhm = " << ell.x_hwhm << ", "; + ostr << "y_hwhm = " << ell.y_hwhm << "\n"; + ostr << "x_offs = " << ell.x_offs << ", "; + ostr << "y_offs = " << ell.y_offs << "\n"; + ostr << "x_lab = " << ell.x_lab << ", "; + ostr << "y_lab = " << ell.y_lab << "\n"; + ostr << "area = " << ell.area; + + return ostr; +} + +template +std::ostream& operator<<(std::ostream& ostr, const Ellipsoid4d& ell) +{ + ostr << "x_hwhm = " << ell.x_hwhm << ", "; + ostr << "y_hwhm = " << ell.y_hwhm << ", "; + ostr << "z_hwhm = " << ell.z_hwhm << ", "; + ostr << "w_hwhm = " << ell.w_hwhm << "\n"; + ostr << "x_offs = " << ell.x_offs << ", "; + ostr << "y_offs = " << ell.y_offs << ", "; + ostr << "z_offs = " << ell.z_offs << ", "; + ostr << "w_offs = " << ell.w_offs << "\n"; + ostr << "x_lab = " << ell.x_lab << ", "; + ostr << "y_lab = " << ell.y_lab << ", "; + ostr << "z_lab = " << ell.z_lab << ", "; + ostr << "w_lab = " << ell.w_lab << "\n"; + ostr << "volume = " << ell.vol; + + return ostr; +} + +// -------------------------------------------------------------------------------- + +template +ublas::vector Ellipse2d::operator()(t_real t) const +{ + ublas::vector vec(2); + + vec[0] = x_hwhm*std::cos(2.*tl::get_pi()*t)*std::cos(phi) + - y_hwhm*std::sin(2.*tl::get_pi()*t)*std::sin(phi) + x_offs; + vec[1] = x_hwhm*std::cos(2.*tl::get_pi()*t)*std::sin(phi) + + y_hwhm*std::sin(2.*tl::get_pi()*t)*std::cos(phi) + y_offs; + + return vec; +} + +template +void Ellipse2d::GetCurvePoints(std::vector& x, std::vector& y, + std::size_t iPoints, t_real *pLRTB) +{ + x.resize(iPoints); + y.resize(iPoints); + + for(std::size_t i=0; i vec = operator()(dT); + + x[i] = vec[0]; + y[i] = vec[1]; + } + + if(pLRTB) // bounding rect + { + auto pairX = std::minmax_element(x.begin(), x.end()); + auto pairY = std::minmax_element(y.begin(), y.end()); + + *(pLRTB+0) = *pairX.first; // left + *(pLRTB+1) = *pairX.second; // right + *(pLRTB+2) = *pairY.second; // top + *(pLRTB+3) = *pairY.first; // bottom + } +} + +// -------------------------------------------------------------------------------- + +template +static void elli_gauss_int(tl::QuadEllipsoid& quad, std::size_t iIdx) +{ + //tl::log_debug("before int: ", quad.GetR()); + + ublas::vector vecRint = ellipsoid_gauss_int(quad.GetR(), quad.GetQ(), iIdx); + ublas::matrix matQint = ellipsoid_gauss_int(quad.GetQ(), iIdx); + quad.RemoveElems(iIdx); + quad.SetQ(matQint); + quad.SetR(vecRint); + + //tl::log_debug("after int: ", quad.GetR()); +} + + +static const std::string g_strLabels[] = {"Q_{para} (1/A)", "Q_{ortho} (1/A)", "Q_z (1/A)", "E (meV)"}; +static const std::string g_strLabelsHKL[] = {"h (rlu)", "k (rlu)", "l (rlu)", "E (meV)"}; +static const std::string g_strLabelsHKLOrient[] = {"Reflex 1 (rlu)", "Reflex 2 (rlu)", "Up (rlu)", "E (meV)"}; + +static inline const std::string& ellipse_labels(int iCoord, EllipseCoordSys sys) +{ + switch(sys) + { + case EllipseCoordSys::RLU: + return g_strLabelsHKL[iCoord]; + case EllipseCoordSys::RLU_ORIENT: + return g_strLabelsHKLOrient[iCoord]; + case EllipseCoordSys::AUTO: + case EllipseCoordSys::Q_AVG: + default: + return g_strLabels[iCoord]; + } +} + + +/* + * this is a 1:1 C++ reimplementation of 'proj_elip' from 'mcresplot' + * iX, iY: dimensions to plot + * iInt: dimension to integrate + * iRem1, iRem2: dimensions to remove + */ +template +Ellipse2d calc_res_ellipse( + const ublas::matrix& reso, // quadratic part of quadric + const ublas::vector& reso_vec, // linear part + t_real reso_const, // const part + const ublas::vector& Q_avg, + int iX, int iY, int iInt, int iRem1, int iRem2) +{ + Ellipse2d ell; + ell.quad.SetDim(4); + ell.quad.SetQ(reso); + ell.quad.SetR(reso_vec); + //ell.quad.SetS(reso_const); + + ell.x_offs = ell.y_offs = 0.; + + // labels only valid for non-rotated system + ell.x_lab = g_strLabels[iX]; + ell.y_lab = g_strLabels[iY]; + + + ublas::vector Q_offs = Q_avg; + + if(iRem1>-1) + { + ell.quad.RemoveElems(iRem1); + Q_offs = tl::remove_elem(Q_offs, iRem1); + + if(iInt>=iRem1) --iInt; + if(iRem2>=iRem1) --iRem2; + if(iX>=iRem1) --iX; + if(iY>=iRem1) --iY; + } + + if(iRem2>-1) + { + ell.quad.RemoveElems(iRem2); + Q_offs = tl::remove_elem(Q_offs, iRem2); + + if(iInt>=iRem2) --iInt; + if(iX>=iRem2) --iX; + if(iY>=iRem2) --iY; + } + + if(iInt>-1) + { + elli_gauss_int(ell.quad, iInt); + Q_offs = tl::remove_elem(Q_offs, iInt); + + if(iX>=iInt) --iX; + if(iY>=iInt) --iY; + } + + std::vector evals; + ublas::matrix matRot; + + tl::QuadEllipsoid quad(2); + ell.quad.GetPrincipalAxes(matRot, evals, &quad); + //tl::log_debug("old: ", ell.quad.GetR(), ", new: ", quad.GetR()); + + /*std::cout << "matrix: " << ell.quad.GetQ() << std::endl; + for(t_real dEval : evals) + std::cout << "evals: " << dEval << ", "; + std::cout << "\nevecs: " << matRot << std::endl; + std::cout << std::endl;*/ + + ell.phi = tl::rotation_angle(matRot)[0]; + + // test: set rotation directly + //ublas::matrix matEvecs = tl::rotation_matrix_2d(ell.phi); + //quad.SetR(ublas::prod(matEvecs, ell.quad.GetR())); + + + // if rotation angle >= 90° -> choose other axis as first axis + /*if(std::fabs(ell.phi) >= M_PI/2.) + { + std::swap(evecs[0], evecs[1]); + std::swap(evals[0], evals[1]); + evecs[0] = -evecs[0]; + + if(ell.phi < 0.) + evecs[0] = -evecs[0]; + + evecs_rot = column_matrix(evecs); + ell.phi = rotation_angle(evecs_rot)[0]; + }*/ + + /*if(std::fabs(ell.phi) > std::fabs(M_PI-std::fabs(ell.phi))) + { + evecs[0] = -evecs[0]; + evecs_rot = column_matrix(evecs); + ell.phi = rotation_angle(evecs_rot)[0]; + }*/ + + + ell.x_hwhm = tl::SIGMA2HWHM * quad.GetRadius(0); + ell.y_hwhm = tl::SIGMA2HWHM * quad.GetRadius(1); + + ell.x_offs = Q_offs[iX]; + ell.y_offs = Q_offs[iY]; + + // linear part of quadric + ublas::vector vecTrans = quad.GetPrincipalOffset(); + + // matrix from eigenvectors is not necessarily SO(2), + // but could contain a reflection + if(ell.phi < t_real(0)) + vecTrans[0] = -vecTrans[0]; + + if(vecTrans.size() == 2) + { + ell.x_offs += vecTrans[0]; + ell.y_offs += vecTrans[1]; + } + else + { + tl::log_err("Invalid ellipse shift."); + } + + ell.area = quad.GetVolume(); + ell.slope = std::tan(ell.phi); + + +#ifndef NDEBUG + // sanity check, see Shirane p. 267 + ublas::matrix res_mat0 = ell.quad.GetQ(); + t_real dMyPhi = tl::r2d(ell.phi); + t_real dPhiShirane = tl::r2d(t_real(0.5)*atan(2.*res_mat0(0,1) / (res_mat0(0,0)-res_mat0(1,1)))); + if(!tl::float_equal(dMyPhi, dPhiShirane, 0.01) + && !tl::float_equal(dMyPhi-90., dPhiShirane, 0.01)) + { + tl::log_warn("Calculated ellipse phi = ", dMyPhi, " deg", + " deviates from theoretical phi = ", dPhiShirane, " deg."); + } +#endif + + return ell; +} + +// -------------------------------------------------------------------------------- + +template +Ellipsoid3d calc_res_ellipsoid( + const ublas::matrix& reso, + const ublas::vector& reso_vec, + t_real reso_const, + const ublas::vector& Q_avg, + int iX, int iY, int iZ, int iInt, int iRem) +{ + Ellipsoid3d ell; + + ell.quad.SetDim(4); + ell.quad.SetQ(reso); + ell.quad.SetR(reso_vec); + //ell.quad.SetS(reso_const); + + ell.x_offs = ell.y_offs = ell.z_offs = 0.; + + // labels only valid for non-rotated system + ell.x_lab = g_strLabels[iX]; + ell.y_lab = g_strLabels[iY]; + ell.z_lab = g_strLabels[iZ]; + + + ublas::vector Q_offs = Q_avg; + + if(iRem>-1) + { + ell.quad.RemoveElems(iRem); + Q_offs = tl::remove_elem(Q_offs, iRem); + + if(iInt>=iRem) --iInt; + if(iX>=iRem) --iX; + if(iY>=iRem) --iY; + if(iZ>=iRem) --iZ; + } + + if(iInt>-1) + { + elli_gauss_int(ell.quad, iInt); + Q_offs = tl::remove_elem(Q_offs, iInt); + + if(iX>=iInt) --iX; + if(iY>=iInt) --iY; + if(iZ>=iInt) --iZ; + } + + std::vector evals; + tl::QuadEllipsoid quad(3); + ell.quad.GetPrincipalAxes(ell.rot, evals, &quad); + + //tl::log_info("Principal axes: ", quad.GetQ()); + ell.x_hwhm = tl::SIGMA2HWHM * quad.GetRadius(0); + ell.y_hwhm = tl::SIGMA2HWHM * quad.GetRadius(1); + ell.z_hwhm = tl::SIGMA2HWHM * quad.GetRadius(2); + + ell.x_offs = Q_offs[iX]; + ell.y_offs = Q_offs[iY]; + ell.z_offs = Q_offs[iZ]; + + // linear part of quadric + const ublas::vector vecTrans = quad.GetPrincipalOffset(); + + if(vecTrans.size() == 3) + { + ell.x_offs += vecTrans[0]; + ell.y_offs += vecTrans[1]; + ell.z_offs += vecTrans[2]; + } + else + { + tl::log_err("Invalid ellipsoid shift."); + } + + ell.vol = quad.GetVolume(); + return ell; +} + +// -------------------------------------------------------------------------------- + +template +Ellipsoid4d calc_res_ellipsoid4d( + const ublas::matrix& reso, + const ublas::vector& reso_vec, + t_real reso_const, + const ublas::vector& Q_avg) +{ + Ellipsoid4d ell; + ell.quad.SetDim(4); + ell.quad.SetQ(reso); + ell.quad.SetR(reso_vec); + //ell.quad.SetS(reso_const); + + std::vector evals; + tl::QuadEllipsoid quad(4); + ell.quad.GetPrincipalAxes(ell.rot, evals, &quad); + + ell.x_hwhm = tl::SIGMA2HWHM * quad.GetRadius(0); + ell.y_hwhm = tl::SIGMA2HWHM * quad.GetRadius(1); + ell.z_hwhm = tl::SIGMA2HWHM * quad.GetRadius(2); + ell.w_hwhm = tl::SIGMA2HWHM * quad.GetRadius(3); + + ell.x_offs = Q_avg[0]; + ell.y_offs = Q_avg[1]; + ell.z_offs = Q_avg[2]; + ell.w_offs = Q_avg[3]; + + // linear part of quadric + const ublas::vector vecTrans = quad.GetPrincipalOffset(); + + if(vecTrans.size() == 4) + { + ell.x_offs += vecTrans[0]; + ell.y_offs += vecTrans[1]; + ell.z_offs += vecTrans[2]; + ell.w_offs += vecTrans[3]; + } + else + { + tl::log_err("Invalid ellipsoid shift."); + } + + // labels only valid for non-rotated system + ell.x_lab = g_strLabels[0]; + ell.y_lab = g_strLabels[1]; + ell.z_lab = g_strLabels[2]; + ell.w_lab = g_strLabels[3]; + + ell.vol = quad.GetVolume(); + + //std::cout << ell << std::endl; + return ell; +} + +#endif diff --git a/tools/res/mc.h b/tools/res/mc.h new file mode 100644 index 0000000..ec5a56b --- /dev/null +++ b/tools/res/mc.h @@ -0,0 +1,107 @@ +/** + * monte carlo neutrons + * @author tweber + * @date 2014 + * @license GPLv2 + */ + +#ifndef __MC_NEUTR_H__ +#define __MC_NEUTR_H__ + + +#include +#include +#include +#include + +#include +#include +namespace ublas = boost::numeric::ublas; + +#include "tlibs/math/math.h" +#include "tlibs/math/rand.h" + + +enum class McNeutronCoords +{ + DIRECT = 0, + ANGS = 1, + RLU = 2 +}; + +template> +struct McNeutronOpts +{ + using real_type = typename t_mat::value_type; + + McNeutronCoords coords = McNeutronCoords::RLU; + t_mat matU, matB, matUB; + t_mat matUinv, matBinv, matUBinv; + real_type dAngleQVec0; + + bool bCenter; +}; + + + +/** + * Ellipsoid E in Q||... coord. system in 1/A + * + * matQVec0: trafo from Q||... to orient1, orient2 system in 1/A + * Uinv * matQVec0: trafo from Q||... system to lab 1/A system + * Binv * Uinv * matQVec0: trafo from Q||... system to crystal rlu system + */ +template, class t_mat=ublas::matrix, + class t_iter = typename std::vector::iterator> +void mc_neutrons(const Ellipsoid4d& ell4d, + std::size_t iNum, const McNeutronOpts& opts, t_iter iterResult) +{ + static bool bInited = 0; + if(!bInited) + { + tl::init_rand(); + bInited = 1; + } + + t_vec vecTrans(4); + vecTrans[0] = ell4d.x_offs; + vecTrans[1] = ell4d.y_offs; + vecTrans[2] = ell4d.z_offs; + vecTrans[3] = ell4d.w_offs; + + const t_mat& rot = ell4d.rot; + //if(vecResult.size() != iNum) + // vecResult.resize(iNum); + + //tl::log_debug("rot: ", rot); + //tl::log_debug("Qvec0 = ", opts.dAngleQVec0/M_PI*180.); + t_mat matQVec0 = tl::rotation_matrix_2d(-opts.dAngleQVec0); + matQVec0.resize(4,4, true); + matQVec0(2,2) = matQVec0(3,3) = 1.; + matQVec0(2,0) = matQVec0(2,1) = matQVec0(2,3) = 0.; + matQVec0(3,0) = matQVec0(3,1) = matQVec0(3,2) = 0.; + matQVec0(0,2) = matQVec0(0,3) = 0.; + matQVec0(1,2) = matQVec0(1,3) = 0.; + + t_mat matUBinvQVec0 = ublas::prod(opts.matUBinv, matQVec0); + + for(std::size_t iCur=0; iCur({0.,0.,0.,0.}, + {ell4d.x_hwhm*tl::HWHM2SIGMA, ell4d.y_hwhm*tl::HWHM2SIGMA, + ell4d.z_hwhm*tl::HWHM2SIGMA, ell4d.w_hwhm*tl::HWHM2SIGMA}); + + vecMC = ublas::prod(rot, vecMC); + if(!opts.bCenter) + vecMC += vecTrans; + + if(opts.coords == McNeutronCoords::ANGS) + vecMC = ublas::prod(matQVec0, vecMC); + else if(opts.coords == McNeutronCoords::RLU) + vecMC = ublas::prod(matUBinvQVec0, vecMC); + + iterResult[iCur] = std::move(vecMC); + } +} + +#endif diff --git a/tools/res/pop.cpp b/tools/res/pop.cpp new file mode 100644 index 0000000..e89136f --- /dev/null +++ b/tools/res/pop.cpp @@ -0,0 +1,394 @@ +/** + * popovici calculation + * @author tweber + * @date 2013-2016 + * @license GPLv2 + * + * @desc This is a reimplementation in C++ of the file rc_popma.m of the + * rescal5 package by Zinkin, McMorrow, Tennant, Farhi, and Wildes: + * http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/ + * @desc see: [pop75] M. Popovici, Acta Cryst. A 31, 507 (1975) + */ + +#include "pop.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/math.h" + +#include +#include + + +typedef t_real_reso t_real; +typedef ublas::matrix t_mat; +typedef ublas::vector t_vec; + +using angle = tl::t_angle_si; +using wavenumber = tl::t_wavenumber_si; +using energy = tl::t_energy_si; +using length = tl::t_length_si; +using inv_length = tl::t_length_inverse_si; + +static const auto angs = tl::get_one_angstrom(); +static const auto rads = tl::get_one_radian(); +static const auto meV = tl::get_one_meV(); +static const auto cm = tl::get_one_centimeter(); + + +ResoResults calc_pop(const PopParams& pop) +{ + ResoResults res; + + res.Q_avg.resize(4); + res.Q_avg[0] = pop.Q*angs; + res.Q_avg[1] = 0.; + res.Q_avg[2] = 0.; + res.Q_avg[3] = pop.E / meV; + + + length lam = tl::k2lam(pop.ki); + angle twotheta = pop.twotheta; + angle thetaa = pop.thetaa * pop.dana_sense; + angle thetam = pop.thetam * pop.dmono_sense; + angle ki_Q = pop.angle_ki_Q; + angle kf_Q = pop.angle_kf_Q; + //kf_Q = ki_Q + twotheta; + + twotheta *= pop.dsample_sense; + ki_Q *= pop.dsample_sense; + kf_Q *= pop.dsample_sense; + + + t_mat Ti = tl::rotation_matrix_2d(ki_Q/rads); + t_mat Tf = -tl::rotation_matrix_2d(kf_Q/rads); + + // B matrix, [pop75], Appendix 1 -> U matrix in CN + t_mat B = ublas::zero_matrix(4,6); + tl::submatrix_copy(B, Ti, 0, 0); + tl::submatrix_copy(B, Tf, 0, 3); + B(2,2) = 1.; B(2,5) = -1.; + B(3,0) = t_real(2)*pop.ki*angs * tl::get_KSQ2E(); + B(3,3) = t_real(-2)*pop.kf*angs * tl::get_KSQ2E(); + //std::cout << "k^2 to E factor: " << tl::KSQ2E << std::endl; + //std::cout << "B = " << B << std::endl; + + + angle coll_h_pre_mono = pop.coll_h_pre_mono; + angle coll_v_pre_mono = pop.coll_v_pre_mono; + + if(pop.bGuide) + { + coll_h_pre_mono = lam*(pop.guide_div_h/angs); + coll_v_pre_mono = lam*(pop.guide_div_v/angs); + } + + + // collimator covariance matrix G, [pop75], Appendix 1 + t_mat G = tl::diag_matrix({ + t_real(1)/(coll_h_pre_mono*coll_h_pre_mono /rads/rads), + t_real(1)/(pop.coll_h_pre_sample*pop.coll_h_pre_sample /rads/rads), + + t_real(1)/(coll_v_pre_mono*coll_v_pre_mono /rads/rads), + t_real(1)/(pop.coll_v_pre_sample*pop.coll_v_pre_sample /rads/rads), + + t_real(1)/(pop.coll_h_post_sample*pop.coll_h_post_sample /rads/rads), + t_real(1)/(pop.coll_h_post_ana*pop.coll_h_post_ana /rads/rads), + + t_real(1)/(pop.coll_v_post_sample*pop.coll_v_post_sample /rads/rads), + t_real(1)/(pop.coll_v_post_ana*pop.coll_v_post_ana /rads/rads) + }); + + + const angle mono_mosaic_spread = pop.mono_mosaic; + const angle ana_mosaic_spread = pop.ana_mosaic; + const angle sample_mosaic_spread = pop.sample_mosaic; + + // crystal mosaic covariance matrix F, [pop75], Appendix 1 + t_mat F = tl::diag_matrix( + { + t_real(1)/(pop.mono_mosaic*pop.mono_mosaic /rads/rads), + t_real(1)/(mono_mosaic_spread*mono_mosaic_spread /rads/rads), + t_real(1)/(pop.ana_mosaic*pop.ana_mosaic /rads/rads), + t_real(1)/(ana_mosaic_spread*ana_mosaic_spread /rads/rads) + }); + + // C matrix, [pop75], Appendix 1 + t_mat C = ublas::zero_matrix(4,8); + C(2,5) = C(2,4) = C(0,1) = C(0,0) = 0.5; + C(1,2) = 0.5/units::sin(thetam); + C(1,3) /*C(2,2)*/ = t_real(-0.5)/units::sin(thetam); // Popovici says C(2,2), not C(1,3) + C(3,6) = t_real(0.5)/units::sin(thetaa); + C(3,7) = t_real(-0.5)/units::sin(thetaa); + + // A matrix, [pop75], Appendix 1 + t_mat A = ublas::zero_matrix(6,8); + A(0,0) = t_real(0.5) * pop.ki*angs * units::cos(thetam)/units::sin(thetam); + A(0,1) = t_real(-0.5) * pop.ki*angs * units::cos(thetam)/units::sin(thetam); + A(2,3) = A(1,1) = pop.ki * angs; + A(3,4) = t_real(0.5) * pop.kf*angs * units::cos(thetaa)/units::sin(thetaa); + A(3,5) = t_real(-0.5) * pop.kf*angs * units::cos(thetaa)/units::sin(thetaa); + A(5,6) = A(4,4) = pop.kf * angs; + + + + // S matrix, [pop75], Appendix 2 + // source + t_real dMult = 1./12.; + if(!pop.bSrcRect) dMult = 1./16.; + t_real dSiSrc[] = + { + dMult * pop.src_w*pop.src_w /cm/cm, + dMult * pop.src_h*pop.src_h /cm/cm + }; + + // mono + t_real dSiMono[] = + { + t_real(1./12.) * pop.mono_thick*pop.mono_thick /cm/cm, + t_real(1./12.) * pop.mono_w*pop.mono_w /cm/cm, + t_real(1./12.) * pop.mono_h*pop.mono_h /cm/cm + }; + + // sample + dMult = 1./12.; + if(!pop.bSampleCub) dMult = 1./16.; + t_real dSiSample[] = + { + dMult * pop.sample_w_perpq *pop.sample_w_perpq /cm/cm, + dMult * pop.sample_w_q*pop.sample_w_q /cm/cm, + t_real(1./12.) * pop.sample_h*pop.sample_h /cm/cm + }; + + // ana + t_real dSiAna[] = + { + t_real(1./12.) * pop.ana_thick*pop.ana_thick /cm/cm, + t_real(1./12.) * pop.ana_w*pop.ana_w /cm/cm, + t_real(1./12.) * pop.ana_h*pop.ana_h /cm/cm + }; + + // det + dMult = 1./12.; + if(!pop.bDetRect) dMult = 1./16.; + t_real dSiDet[] = + { + dMult * pop.det_w*pop.det_w /cm/cm, + dMult * pop.det_h*pop.det_h /cm/cm + }; + + t_mat SI = tl::diag_matrix({dSiSrc[0], dSiSrc[1], + dSiMono[0], dSiMono[1], dSiMono[2], + dSiSample[0], dSiSample[1], dSiSample[2], + dSiAna[0], dSiAna[1], dSiAna[2], + dSiDet[0], dSiDet[1]}); + SI *= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + + t_mat S; + if(!tl::inverse(SI, S)) + { + res.bOk = false; + res.strErr = "S matrix cannot be inverted."; + return res; + } + + + // -------------------------------------------------------------------- + // mono/ana focus + length mono_curvh = pop.mono_curvh, mono_curvv = pop.mono_curvv; + length ana_curvh = pop.ana_curvh, ana_curvv = pop.ana_curvv; + + if(pop.bMonoIsOptimallyCurvedH) mono_curvh = tl::foc_curv(pop.dist_src_mono, pop.dist_mono_sample, units::abs(t_real(2)*thetam), false); + if(pop.bMonoIsOptimallyCurvedV) mono_curvv = tl::foc_curv(pop.dist_src_mono, pop.dist_mono_sample, units::abs(t_real(2)*thetam), true); + if(pop.bAnaIsOptimallyCurvedH) ana_curvh = tl::foc_curv(pop.dist_sample_ana, pop.dist_ana_det, units::abs(t_real(2)*thetaa), false); + if(pop.bAnaIsOptimallyCurvedV) ana_curvv = tl::foc_curv(pop.dist_sample_ana, pop.dist_ana_det, units::abs(t_real(2)*thetaa), true); + + mono_curvh *= pop.dmono_sense; mono_curvv *= pop.dmono_sense; + ana_curvh *= pop.dana_sense; ana_curvv *= pop.dana_sense; + + inv_length inv_mono_curvh = t_real(0)/cm, inv_mono_curvv = t_real(0)/cm; + inv_length inv_ana_curvh = t_real(0)/cm, inv_ana_curvv = t_real(0)/cm; + + if(pop.bMonoIsCurvedH) inv_mono_curvh = t_real(1)/mono_curvh; + if(pop.bMonoIsCurvedV) inv_mono_curvv = t_real(1)/mono_curvv; + if(pop.bAnaIsCurvedH) inv_ana_curvh = t_real(1)/ana_curvh; + if(pop.bAnaIsCurvedV) inv_ana_curvv = t_real(1)/ana_curvv; + + //if(pop.bMonoIsCurvedH) tl::log_debug("mono curv h: ", mono_curvh); + //if(pop.bMonoIsCurvedV) tl::log_debug("mono curv v: ", mono_curvv); + //if(pop.bAnaIsCurvedH) tl::log_debug("ana curv h: ", ana_curvh); + //if(pop.bAnaIsCurvedV) tl::log_debug("ana curv v: ", ana_curvv); + // -------------------------------------------------------------------- + + + + // T matrix, [pop75], Appendix 2 + t_mat T = ublas::zero_matrix(4,13); + T(0,0) = t_real(-0.5) / (pop.dist_src_mono / cm); + T(0,2) = t_real(0.5) * units::cos(thetam) * + (t_real(1)/(pop.dist_mono_sample/cm) - t_real(1)/(pop.dist_src_mono/cm)); + T(0,3) = t_real(0.5) * units::sin(thetam) * + (t_real(1)/(pop.dist_src_mono/cm) + t_real(1)/(pop.dist_mono_sample/cm) - + t_real(2)*inv_mono_curvh*cm/(units::sin(thetam))); + T(0,5) = t_real(0.5) * units::sin(t_real(0.5)*twotheta) / (pop.dist_mono_sample/cm); + T(0,6) = t_real(0.5) * units::cos(t_real(0.5)*twotheta) / (pop.dist_mono_sample/cm); + T(1,1) = t_real(-0.5)/(pop.dist_src_mono/cm * units::sin(thetam)); + T(1,4) = t_real(0.5) * (t_real(1)/(pop.dist_src_mono/cm) + + t_real(1)/(pop.dist_mono_sample/cm) - + t_real(2)*units::sin(thetam)*inv_mono_curvv*cm) + / (units::sin(thetam)); + T(1,7) = t_real(-0.5)/(pop.dist_mono_sample/cm * units::sin(thetam)); + T(2,5) = t_real(0.5)*units::sin(t_real(0.5)*twotheta) / (pop.dist_sample_ana/cm); + T(2,6) = t_real(-0.5)*units::cos(t_real(0.5)*twotheta) / (pop.dist_sample_ana/cm); + T(2,8) = t_real(0.5)*units::cos(thetaa) * (t_real(1)/(pop.dist_ana_det/cm) - + t_real(1)/(pop.dist_sample_ana/cm)); + T(2,9) = t_real(0.5)*units::sin(thetaa) * ( + t_real(1)/(pop.dist_sample_ana/cm) + + t_real(1)/(pop.dist_ana_det/cm) - + t_real(2)*inv_ana_curvh*cm / (units::sin(thetaa))); + T(2,11) = t_real(0.5)/(pop.dist_ana_det/cm); + T(3,7) = t_real(-0.5)/(pop.dist_sample_ana/cm*units::sin(thetaa)); + T(3,10) = t_real(0.5)*(1./(pop.dist_sample_ana/cm) + + t_real(1)/(pop.dist_ana_det/cm) - + t_real(2)*units::sin(thetaa)*inv_ana_curvv*cm) + / (units::sin(thetaa)); + T(3,12) = t_real(-0.5)/(pop.dist_ana_det/cm*units::sin(thetaa)); + + + // D matrix, [pop75], Appendix 2 + t_mat D = ublas::zero_matrix(8,13); + D(0,0) = t_real(-1) / (pop.dist_src_mono/cm); + D(0,2) = -cos(thetam) / (pop.dist_src_mono/cm); + D(0,3) = sin(thetam) / (pop.dist_src_mono/cm); + D(1,2) = cos(thetam) / (pop.dist_mono_sample/cm); + D(1,3) = sin(thetam) / (pop.dist_mono_sample/cm); + D(1,5) = sin(t_real(0.5)*twotheta) / (pop.dist_mono_sample/cm); + D(1,6) = cos(t_real(0.5)*twotheta) / (pop.dist_mono_sample/cm); + D(2,1) = t_real(-1) / (pop.dist_src_mono/cm); + D(2,4) = t_real(1) / (pop.dist_src_mono/cm); + D(3,4) = t_real(-1) / (pop.dist_mono_sample/cm); + D(3,7) = t_real(1) / (pop.dist_mono_sample/cm); + D(4,5) = sin(t_real(0.5)*twotheta) / (pop.dist_sample_ana/cm); + D(4,6) = -cos(t_real(0.5)*twotheta) / (pop.dist_sample_ana/cm); + D(4,8) = -cos(thetaa) / (pop.dist_sample_ana/cm); + D(4,9) = sin(thetaa) / (pop.dist_sample_ana/cm); + D(5,8) = cos(thetaa) / (pop.dist_ana_det/cm); + D(5,9) = sin(thetaa) / (pop.dist_ana_det/cm); + D(5,11) = t_real(1) / (pop.dist_ana_det/cm); + D(6,7) = t_real(-1) / (pop.dist_sample_ana/cm); + D(6,10) = t_real(1) / (pop.dist_sample_ana/cm); + D(7,10) = t_real(-1) / (pop.dist_ana_det/cm); + D(7,12) = t_real(1) / (pop.dist_ana_det/cm); + + + // [pop75], equ. 20 + t_mat M0 = S + tl::transform(F, T, 1); + t_mat M0i; + if(!tl::inverse(M0, M0i)) + { + res.bOk = false; + res.strErr = "Matrix M0 cannot be inverted."; + return res; + } + + t_mat M1 = tl::transform_inv(M0i, D, 1); + t_mat M1i; + if(!tl::inverse(M1, M1i)) + { + res.bOk = false; + res.strErr = "Matrix M1 cannot be inverted."; + return res; + } + + t_mat M2 = M1i + G; + t_mat M2i; + if(!tl::inverse(M2, M2i)) + { + res.bOk = false; + res.strErr = "Matrix M2 cannot be inverted."; + return res; + } + + t_mat BA = ublas::prod(B,A); + t_mat ABt = ublas::prod(ublas::trans(A), ublas::trans(B)); + t_mat M2iABt = ublas::prod(M2i, ABt); + t_mat MI = ublas::prod(BA, M2iABt); + + MI(1,1) += pop.Q*pop.Q*angs*angs * pop.sample_mosaic*pop.sample_mosaic /rads/rads; + MI(2,2) += pop.Q*pop.Q*angs*angs * sample_mosaic_spread*sample_mosaic_spread /rads/rads; + + if(!tl::inverse(MI, res.reso)) + { + res.bOk = false; + res.strErr = "Covariance matrix cannot be inverted."; + return res; + } + + + // ------------------------------------------------------------------------- + + + res.reso *= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + res.reso_v = ublas::zero_vector(4); + res.reso_s = 0.; + + if(pop.dsample_sense < 0.) + { + // mirror Q_perp + t_mat matMirror = tl::mirror_matrix(res.reso.size1(), 1); + res.reso = tl::transform(res.reso, matMirror, true); + res.reso_v[1] = -res.reso_v[1]; + } + + + res.dResVol = tl::get_ellipsoid_volume(res.reso); + res.dR0 = 0.; + const t_real pi = tl::get_pi(); + if(pop.bCalcR0) + { + //SI /= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + //S *= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + + // resolution volume, [pop75], equ. 13a & 16 + // [D] = 1/cm, [SI] = cm^2 + t_mat DSiDt = tl::transform_inv(SI, D, 1); + t_mat DSiDti; + if(!tl::inverse(DSiDt, DSiDti)) + { + res.bOk = false; + res.strErr = "Resolution volume cannot be calculated."; + return res; + } + DSiDti += G; + t_real dP0 = pop.dmono_refl*pop.dana_effic * + t_real((2.*pi)*(2.*pi)*(2.*pi)*(2.*pi)) / + std::sqrt(tl::determinant(DSiDti)); + + // [T] = 1/cm, [F] = 1/rad^2, [pop75], equ. 15 + t_mat K = S + tl::transform(F, T, 1); + + t_real dDetS = tl::determinant(S); + t_real dDetF = tl::determinant(F); + t_real dDetK = tl::determinant(K); + + // [pop75], equ. 16 + res.dR0 = dP0 / (t_real(8.*pi*8.*pi) * units::sin(thetam)*units::sin(thetaa)); + res.dR0 *= std::sqrt(dDetS*dDetF/dDetK); + + // rest of the prefactors, equ. 1 in [pop75] + //res.dR0 *= std::sqrt(tl::determinant(res.reso)) / (2.*pi*2.*pi); + //res.dR0 *= res.dResVol; // TODO: check + } + + // Bragg widths + for(unsigned int i=0; i<4; ++i) + res.dBraggFWHMs[i] = tl::SIGMA2FWHM/sqrt(res.reso(i,i)); + + if(tl::is_nan_or_inf(res.dR0) || tl::is_nan_or_inf(res.reso)) + { + res.strErr = "Invalid result."; + res.bOk = false; + return res; + } + + res.bOk = true; + return res; +} diff --git a/tools/res/pop.h b/tools/res/pop.h new file mode 100644 index 0000000..6218d4f --- /dev/null +++ b/tools/res/pop.h @@ -0,0 +1,64 @@ +/** + * popovici calculation + * @author tweber + * @date 2013-2016 + * @license GPLv2 + * + * @desc This is a reimplementation in C++ of the file rc_popma.m of the + * rescal5 package by Zinkin, McMorrow, Tennant, Farhi, and Wildes: + * http://www.ill.eu/en/instruments-support/computing-for-science/cs-software/all-software/matlab-ill/rescal-for-matlab/ + * @desc see: [pop75] M. Popovici, Acta Cryst. A 31, 507 (1975) + */ + +#ifndef __TAKIN_POP_H__ +#define __TAKIN_POP_H__ + +#include "cn.h" + +struct PopParams : public CNParams +{ + tl::t_length_si mono_w; + tl::t_length_si mono_h; + tl::t_length_si mono_thick; + tl::t_length_si mono_curvh; + tl::t_length_si mono_curvv; + bool bMonoIsCurvedH=0, bMonoIsCurvedV=0; + bool bMonoIsOptimallyCurvedH=0, bMonoIsOptimallyCurvedV=0; + unsigned int mono_numtiles_v, mono_numtiles_h; + + tl::t_length_si ana_w; + tl::t_length_si ana_h; + tl::t_length_si ana_thick; + tl::t_length_si ana_curvh; + tl::t_length_si ana_curvv; + bool bAnaIsCurvedH=0, bAnaIsCurvedV=0; + bool bAnaIsOptimallyCurvedH=0, bAnaIsOptimallyCurvedV=0; + unsigned int ana_numtiles_v, ana_numtiles_h; + + bool bSampleCub=1; + tl::t_length_si sample_w_q; + tl::t_length_si sample_w_perpq; + tl::t_length_si sample_h; + + bool bSrcRect=1; + tl::t_length_si src_w; + tl::t_length_si src_h; + + bool bDetRect=1; + tl::t_length_si det_w; + tl::t_length_si det_h; + + bool bGuide=0; + tl::t_angle_si guide_div_h; + tl::t_angle_si guide_div_v; + + tl::t_length_si dist_mono_sample; + tl::t_length_si dist_sample_ana; + tl::t_length_si dist_ana_det; + tl::t_length_si dist_src_mono; +}; + + +extern ResoResults calc_pop(const PopParams& pop); + +#endif diff --git a/tools/res/res_main.cpp b/tools/res/res_main.cpp new file mode 100644 index 0000000..3c8db62 --- /dev/null +++ b/tools/res/res_main.cpp @@ -0,0 +1,47 @@ +/* + * reso tool + * @author tweber + * @date 2013, 2014 + * @copyright GPLv2 + */ + +#include +#include "ResoDlg.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/log/log.h" + +#ifdef Q_WS_X11 + extern "C" int XInitThreads(); +#endif + +int main(int argc, char** argv) +{ + try + { + tl::log_info("Starting up resolution tool."); + + #ifdef Q_WS_X11 + XInitThreads(); + #endif + + tl::init_spec_chars(); + QApplication app(argc, argv); + + std::setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::English); + + ResoDlg dlg(0); + dlg.show(); + int iRet = app.exec(); + + tl::deinit_spec_chars(); + tl::log_info("Shutting down resolution tool."); + return iRet; + } + catch(const std::exception& ex) + { + tl::log_crit(ex.what()); + } + + return -1; +} diff --git a/tools/res/simple.cpp b/tools/res/simple.cpp new file mode 100644 index 0000000..19919a6 --- /dev/null +++ b/tools/res/simple.cpp @@ -0,0 +1,145 @@ +/** + * simple resolution calculation including only ki and kf errors + * @author Tobias Weber + * @date jun-2016 + * @license GPLv2 + */ + +#include "simple.h" +#include "ellipse.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/geo.h" +#include "tlibs/math/math.h" +#include "tlibs/log/log.h" + +#include +#include + +typedef t_real_reso t_real; +typedef ublas::matrix t_mat; +typedef ublas::vector t_vec; + +using angle = tl::t_angle_si; +using wavenumber = tl::t_wavenumber_si; +using velocity = tl::t_velocity_si; +using t_time = tl::t_time_si; +using energy = tl::t_energy_si; +using length = tl::t_length_si; +using mass = tl::t_mass_si; + +static const auto rads = tl::get_one_radian(); +static const length angs = tl::get_one_angstrom(); +static const energy meV = tl::get_one_meV(); +static const t_time sec = tl::get_one_second(); +static const length meter = tl::get_one_meter(); + + +ResoResults calc_simplereso(const SimpleResoParams& params) +{ + ResoResults res; + res.Q_avg.resize(4); + + //const energy E = params.E; + //const wavenumber Q = params.Q; + const angle& tt = params.twotheta; + const wavenumber &ki = params.ki, &kf = params.kf; + const energy E = tl::get_energy_transfer(ki, kf); + const wavenumber Q = tl::get_sample_Q(ki, kf, tt); + + res.Q_avg[0] = Q * angs; + res.Q_avg[1] = 0.; + res.Q_avg[2] = 0.; + res.Q_avg[3] = E / meV; + +#ifndef NDEBUG + tl::log_debug("ki = ", ki, ", kf = ", kf); + tl::log_debug("Q = ", Q, ", E = ", E); +#endif + + const mass mn = tl::get_m_n(); + const auto hbar = tl::get_hbar(); + + + const t_real ctt = units::cos(tt); + const t_real stt = units::sin(tt); + + // -------------------------------------------------------------------- + // sigmas + const wavenumber& sig_kix = params.sig_ki; + const wavenumber sig_kiy = params.sig_ki_perp; + const wavenumber sig_kiz = params.sig_ki_z; + + const wavenumber sig_kfx = params.sig_kf * ctt - params.sig_kf_perp * stt; + const wavenumber sig_kfy = params.sig_kf * stt + params.sig_kf_perp * ctt; + const wavenumber sig_kfz = params.sig_kf_z; + + t_mat matSigSq = tl::diag_matrix({ + sig_kix*sig_kix * angs*angs, + sig_kiy*sig_kiy * angs*angs, + sig_kiz*sig_kiz * angs*angs, + sig_kfx*sig_kfx * angs*angs, + sig_kfy*sig_kfy * angs*angs, + sig_kfz*sig_kfz * angs*angs }); + + + // -------------------------------------------------------------------- + // values + const wavenumber& kix = ki; + const wavenumber kiy = t_real(0)/angs; + const wavenumber kiz = t_real(0)/angs; + + const wavenumber kfx = kf * ctt; + const wavenumber kfy = kf * stt; + const wavenumber kfz = t_real(0)/angs; + + // Matrix of derivatives of: + // Q = ki - kf and E = hbar^2/(2mn)*(ki^2 - kf^2) + t_mat matJacobiInstr(4, matSigSq.size1(), t_real(0)); + matJacobiInstr(0,0) = matJacobiInstr(1,1) = matJacobiInstr(2,2) = t_real(1); + matJacobiInstr(0,3) = matJacobiInstr(1,4) = matJacobiInstr(2,5) = t_real(-1); + matJacobiInstr(3,0) = hbar*hbar/mn * kix /angs/meV; + matJacobiInstr(3,1) = hbar*hbar/mn * kiy /angs/meV; + matJacobiInstr(3,2) = hbar*hbar/mn * kiz /angs/meV; + matJacobiInstr(3,3) = -hbar*hbar/mn * kfx /angs/meV; + matJacobiInstr(3,4) = -hbar*hbar/mn * kfy /angs/meV; + matJacobiInstr(3,5) = -hbar*hbar/mn * kfz /angs/meV; + + t_mat matSigQE = tl::transform_inv(matSigSq, matJacobiInstr, true); + if(!tl::inverse(matSigQE, res.reso)) + { + //tl::log_err(matSigQE); + res.bOk = false; + res.strErr = "Jacobi matrix cannot be inverted."; + return res; + } + +#ifndef NDEBUG + tl::log_debug("J_instr = ", matJacobiInstr); + tl::log_debug("J_QE = ", matSigQE); + tl::log_debug("Reso = ", res.reso); +#endif + // -------------------------------------------------------------------- + + // transform from (ki, ki_perp, Qz) to (Q_perp, Q_para, Q_z) system + t_mat matKiQ = tl::rotation_matrix_2d(-params.angle_ki_Q / rads); + matKiQ.resize(4,4, true); + matKiQ(2,2) = matKiQ(3,3) = 1.; + matKiQ(2,0) = matKiQ(2,1) = matKiQ(2,3) = matKiQ(3,0) = matKiQ(3,1) = + matKiQ(3,2) = matKiQ(0,2) = matKiQ(0,3) = matKiQ(1,2) = matKiQ(1,3) = 0.; + + res.reso = tl::transform(res.reso, matKiQ, true); + //res.reso *= tl::SIGMA2FWHM*tl::SIGMA2FWHM; + + res.dResVol = tl::get_ellipsoid_volume(res.reso); + res.dR0 = 0.; // TODO + + // Bragg widths + for(unsigned int i=0; i<4; ++i) + res.dBraggFWHMs[i] = tl::SIGMA2FWHM/sqrt(res.reso(i,i)); + + res.reso_v = ublas::zero_vector(4); + res.reso_s = 0.; + + res.bOk = true; + return res; +} diff --git a/tools/res/simple.h b/tools/res/simple.h new file mode 100644 index 0000000..7ed53b1 --- /dev/null +++ b/tools/res/simple.h @@ -0,0 +1,36 @@ +/** + * simple resolution calculation including only ki and kf errors + * @author Tobias Weber + * @date jun-2016 + * @license GPLv2 + */ + +#ifndef __SIMPLERESO_H__ +#define __SIMPLERESO_H__ + +#include "defs.h" +#include "tlibs/math/neutrons.h" + +namespace units = boost::units; +namespace codata = boost::units::si::constants::codata; + + +struct SimpleResoParams +{ + // values + tl::t_wavenumber_si ki, kf, Q; + tl::t_energy_si E; + + tl::t_angle_si twotheta, + angle_ki_Q, angle_kf_Q; + + // sigmas + tl::t_wavenumber_si sig_ki, sig_kf; + tl::t_wavenumber_si sig_ki_perp, sig_kf_perp; + tl::t_wavenumber_si sig_ki_z, sig_kf_z; +}; + + +extern ResoResults calc_simplereso(const SimpleResoParams& params); + +#endif diff --git a/tools/res/viol.cpp b/tools/res/viol.cpp new file mode 100644 index 0000000..0ea4040 --- /dev/null +++ b/tools/res/viol.cpp @@ -0,0 +1,314 @@ +/** + * implementation of Violini's TOF reso algorithm + * @author Tobias Weber + * @date apr-2016 + * @license GPLv2 + * + * @desc for used algo, see: [viol14] N. Violini et al., NIM A 736 (2014) pp. 31-39 + * @desc results checked with: [ehl11] G. Ehlers et al., http://arxiv.org/abs/1109.1482 (2011) + */ + +#include "viol.h" +#include "ellipse.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/geo.h" +#include "tlibs/math/math.h" +#include "tlibs/log/log.h" + +#include +#include + +typedef t_real_reso t_real; +typedef ublas::matrix t_mat; +typedef ublas::vector t_vec; + +using angle = tl::t_angle_si; +using wavenumber = tl::t_wavenumber_si; +using velocity = tl::t_velocity_si; +using t_time = tl::t_time_si; +using energy = tl::t_energy_si; +using length = tl::t_length_si; +using mass = tl::t_mass_si; + +static const auto rads = tl::get_one_radian(); +static const length angs = tl::get_one_angstrom(); +static const energy meV = tl::get_one_meV(); +static const t_time sec = tl::get_one_second(); +static const length meter = tl::get_one_meter(); + + +ResoResults calc_viol(const ViolParams& params) +{ + ResoResults res; + res.Q_avg.resize(4); + + //const energy E = params.E; + //const wavenumber Q = params.Q; + const angle& tt = params.twotheta; + const wavenumber &ki = params.ki, &kf = params.kf; + const energy E = tl::get_energy_transfer(ki, kf); + const wavenumber Q = tl::get_sample_Q(ki, kf, tt); + + res.Q_avg[0] = Q * angs; + res.Q_avg[1] = 0.; + res.Q_avg[2] = 0.; + res.Q_avg[3] = E / meV; + + const velocity vi = tl::k2v(ki); + const velocity vf = tl::k2v(kf); + + const length& lp = params.len_pulse_mono, + &lm = params.len_mono_sample, + &ls = params.len_sample_det; + const length& slp = params.sig_len_pulse_mono, + &slm = params.sig_len_mono_sample, + &sls = params.sig_len_sample_det; + const angle &tt_i = params.twotheta_i, + &ph_i = params.angle_outplane_i, + &ph_f = params.angle_outplane_f; + + const t_time &sp = params.sig_pulse, + &sm = params.sig_mono, + &sd = params.sig_det; + const angle &s2ti = params.sig_twotheta_i, + &s2tf = params.sig_twotheta_f, + &sphi = params.sig_outplane_i, + &sphf = params.sig_outplane_f; + const t_time ti = lp / vi, + tf = ls / vf; + +#ifndef NDEBUG + tl::log_debug("ki = ", ki, ", kf = ", kf); + tl::log_debug("vi = ", vi, ", vf = ", vf); + tl::log_debug("ti = ", ti, ", tf = ", tf); + tl::log_debug("Q = ", Q, ", E = ", E); +#endif + + const mass mn = tl::get_m_n(); + const auto mn_hbar = mn / tl::get_hbar(); + + // formulas 20 & 21 in [viol14] + const t_time st = tl::my_units_sqrt(sp*sp + sm*sm); + const t_time stm = tl::my_units_sqrt(sd*sd + sm*sm); + + std::vector vecsigs = { st/sec, stm/sec, slp/meter, slm/meter, sls/meter, + s2ti/rads, sphi/rads, s2tf/rads, sphf/rads }; + + + + // -------------------------------------------------------------------- + // E formulas 14-18 in [viol14] + + std::vector> vecEderivs = + { + /*1*/ [&]()->t_real { return (-mn*lp*lp/(ti*ti*ti) -mn*ls*ls/(tf*tf*tf)*lm/lp) /meV*sec; }, + /*2*/ [&]()->t_real { return mn*ls*ls/(tf*tf*tf) /meV*sec; }, + /*3*/ [&]()->t_real { return (mn*lp/(ti*ti) + mn*(ls*ls)/(tf*tf*tf)*ti/(lp*lp)*lm) /meV*meter; }, + /*4*/ [&]()->t_real { return -mn*(ls*ls)/(tf*tf*tf) * ti/lp /meV*meter; }, + /*5*/ [&]()->t_real { return -mn*ls/(tf*tf) /meV*meter; }, + }; + + +#ifndef NDEBUG + // formula 19 in [viol14] + t_real sigE = std::sqrt( + std::inner_product(vecEderivs.begin(), vecEderivs.end(), vecsigs.begin(), t_real(0), + [](t_real r1, t_real r2)->t_real { return r1 + r2; }, + [](const std::function& f1, t_real r2)->t_real { return f1()*f1()*r2*r2; } )); + tl::log_debug("dE (Vanadium fwhm) = ", tl::SIGMA2FWHM*sigE); + + + // -------------------------------------------------------------------- + // checking results against the E resolution formula from [ehl11], p. 6 + auto vi3 = vi*vi*vi/lp; auto vf3 = vf*vf*vf/ls; + ublas::vector vecE2 = tl::make_vec>( + { + mn * sp * (vi3 + vf3*lm/lp), + mn * sm * (vi3 + vf3*(lp+lm)/lp), + mn * sd * vf3 + }); + t_real sigE2 = tl::my_units_norm2(vecE2) / meV; + tl::log_debug("dE (Vanadium fwhm, check) = ", tl::SIGMA2FWHM*sigE2); + // -------------------------------------------------------------------- + +#endif + // -------------------------------------------------------------------- + + + + // -------------------------------------------------------------------- + // spherical: Q formulas in appendices A.1 and p. 34 of [viol14] + // cylindrical: Q formulas in appendices A.3 and p. 35 of [viol14] + + t_real ctt_i = std::cos(tt_i/rads), stt_i = std::sin(tt_i/rads); + t_real ctt_f = std::cos(tt/rads), stt_f = std::sin(tt/rads); + t_real cph_i = std::cos(ph_i/rads), sph_i = std::sin(ph_i/rads); + t_real cph_f = std::cos(ph_f/rads), sph_f = std::sin(ph_f/rads); + t_real tph_f = std::tan(ph_f/rads), dtph_f = t_real(1) + std::pow(std::tan(ph_f/rads), t_real(2)); + + t_mat R, R_tt_f, R_ph_f; + t_mat R_tt_i = tl::make_mat( // R derivs w.r.t the angles + {{ -stt_i*cph_i, t_real(0) }, + { ctt_i*cph_i, t_real(0) }, + { t_real(0), t_real(0) }}); + t_mat R_ph_i = tl::make_mat( + {{ -ctt_i*sph_i, t_real(0) }, + { -stt_i*sph_i, t_real(0) }, + { cph_i, t_real(0) }}); + + if(params.det_shape == TofDetShape::SPH) + { + R = tl::make_mat( // R: spherical coordinates + {{ ctt_i*cph_i, -ctt_f*cph_f }, + { stt_i*cph_i, -stt_f*cph_f }, + { sph_i, -sph_f }}); + R_tt_f = tl::make_mat( // R derivs w.r.t the angles + {{ t_real(0), stt_f*cph_f }, + { t_real(0), -ctt_f*cph_f }, + { t_real(0), t_real(0) }}); + R_ph_f = tl::make_mat( + {{ t_real(0), ctt_f*sph_f }, + { t_real(0), stt_f*sph_f }, + { t_real(0), -cph_f }}); + } + else if(params.det_shape == TofDetShape::CYL) + { // modified original formulas; TODO: check if still correct + R = tl::make_mat( // R: cylindrical coordinates + {{ ctt_i*cph_i, -ctt_f }, + { stt_i*cph_i, -stt_f }, + { sph_i, -tph_f }}); + R_tt_f = tl::make_mat( // R derivs w.r.t the angles + {{ t_real(0), stt_f }, + { t_real(0), -ctt_f }, + { t_real(0), t_real(0) }}); + R_ph_f = tl::make_mat( + {{ t_real(0), t_real(0) }, + { t_real(0), t_real(0) }, + { t_real(0), -dtph_f }}); + } + else + { + res.bOk = false; + res.strErr = "Unknown detector shape."; + return res; + } + // tl::log_debug("R = ", R); + + t_vec vecViVf = tl::make_vec({ mn_hbar*vi *angs, mn_hbar*vf *angs }); + std::vector> vecQderivs = + { + /*1*/ [&]()->t_vec { return ublas::prod(R, tl::make_vec( + { -mn_hbar*vi/ti *angs*sec, mn_hbar*vf/tf * lm/lp *angs*sec })); }, + /*2*/ [&]()->t_vec { return ublas::prod(R, tl::make_vec( + { t_real(0), -mn_hbar*vf/tf *angs*sec })); }, + /*3*/ [&]()->t_vec { return ublas::prod(R, tl::make_vec( + { mn_hbar/ti *angs*meter, -mn_hbar*vf/tf * lm/(vi*lp) *angs*meter })); }, + /*4*/ [&]()->t_vec { return ublas::prod(R, tl::make_vec( + { t_real(0), mn_hbar*vf/tf / vi *angs*meter })); }, + /*5*/ [&]()->t_vec { return ublas::prod(R, tl::make_vec( + { t_real(0), mn_hbar/tf *angs*meter })); }, + + /*6*/ [&]()->t_vec { return ublas::prod(R_tt_i, vecViVf); }, + /*7*/ [&]()->t_vec { return ublas::prod(R_ph_i, vecViVf); }, + /*8*/ [&]()->t_vec { return ublas::prod(R_tt_f, vecViVf); }, + /*9*/ [&]()->t_vec { return ublas::prod(R_ph_f, vecViVf); }, + }; + + +#ifndef NDEBUG + t_vec vecQsq = std::inner_product(vecQderivs.begin(), vecQderivs.end(), + vecsigs.begin(), tl::make_vec({0,0,0}), + [](const t_vec& vec1, const t_vec& vec2) -> t_vec { return vec1 + vec2; }, + [](const std::function& f1, const t_real r2) -> t_vec + { + const t_vec vec1 = f1(); + return ublas::element_prod(vec1, vec1) * r2*r2; + }); + + t_vec sigQ = tl::apply_fkt(vecQsq, static_cast(std::sqrt)); + tl::log_debug("dQ (Vanadium fwhm) = ", tl::SIGMA2FWHM*sigQ); + + + // -------------------------------------------------------------------- + // checking results against the Q resolution formulas from [ehl11], pp. 6-7 + auto vi2 = vi*vi/lp; auto vf2 = vf*vf/ls; + ublas::vector vecQ2[] = { + tl::make_vec>( + { + mn_hbar * sp * (vi2 + vf2*lm/lp * ctt_f), + mn_hbar * sm * (vi2 + vf2*(lp+lm)/lp * ctt_f), + mn_hbar * sd * (vf2 * ctt_f), + mn_hbar * s2tf/rads * (vf * stt_f) + }), + tl::make_vec>( + { + mn_hbar * sp * (vf2*lm/lp * stt_f), + mn_hbar * sm * (vf2*(lp+lm)/lp * stt_f), + mn_hbar * sd * (vf2 * stt_f), + mn_hbar * s2tf/rads * (vf * ctt_f) + }) }; + + t_vec sigQ2 = tl::make_vec({ + tl::my_units_norm2(vecQ2[0]) * angs, + tl::my_units_norm2(vecQ2[1]) * angs }); + tl::log_debug("dQ (Vanadium fwhm, check) = ", tl::SIGMA2FWHM*sigQ2); + // -------------------------------------------------------------------- + +#endif + // -------------------------------------------------------------------- + + + + // -------------------------------------------------------------------- + // formulas 10 & 11 in [viol14] + t_mat matSigSq = tl::diag_matrix({ + st*st /sec/sec, stm*stm /sec/sec, + slp*slp /meter/meter, slm*slm /meter/meter, sls*sls /meter/meter, + s2ti*s2ti /rads/rads, sphi*sphi /rads/rads, + s2tf*s2tf /rads/rads, sphf*sphf /rads/rads }); + + std::size_t N = matSigSq.size1(); + t_mat matJacobiInstr(4, N, t_real(0)); + for(std::size_t iDeriv=0; iDeriv ki, kf, Q; + tl::t_energy_si E; + + tl::t_angle_si twotheta, + angle_ki_Q, angle_kf_Q; + + tl::t_angle_si angle_outplane_i, angle_outplane_f; + tl::t_angle_si twotheta_i; + + + // instrument lengths + tl::t_length_si len_pulse_mono, + len_mono_sample, len_sample_det; + + + // instrument sigmas + tl::t_length_si sig_len_pulse_mono, + sig_len_mono_sample, sig_len_sample_det; + + tl::t_time_si sig_pulse, sig_mono, sig_det; + + tl::t_angle_si sig_twotheta_f, sig_outplane_f, + sig_twotheta_i, sig_outplane_i; + + + TofDetShape det_shape = TofDetShape::SPH; +}; + + +extern ResoResults calc_viol(const ViolParams& params); + +#endif diff --git a/tools/scanviewer/main.cpp b/tools/scanviewer/main.cpp new file mode 100644 index 0000000..32d8607 --- /dev/null +++ b/tools/scanviewer/main.cpp @@ -0,0 +1,26 @@ +/* + * Scan viewer + * @author tweber + * @date mar-2015 + * @copyright GPLv2 + */ + +#include +#include +#include +#include "scanviewer.h" + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + std::setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::English); + + ScanViewerDlg dlg(0); + dlg.setWindowFlags(Qt::Window); + dlg.show(); + + int iRet = app.exec(); + return iRet; +} diff --git a/tools/scanviewer/scanviewer.cpp b/tools/scanviewer/scanviewer.cpp new file mode 100644 index 0000000..cee899a --- /dev/null +++ b/tools/scanviewer/scanviewer.cpp @@ -0,0 +1,687 @@ +/* + * Scan viewer + * @author tweber + * @date mar-2015 + * @license GPLv2 + */ + +#include "scanviewer.h" +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" + +using t_real = t_real_glob; +namespace fs = boost::filesystem; + + +#ifndef QWT_VER + #define QWT_VER 6 +#endif + + +ScanViewerDlg::ScanViewerDlg(QWidget* pParent) + : QDialog(pParent, Qt::WindowTitleHint|Qt::WindowCloseButtonHint|Qt::WindowMinMaxButtonsHint), + m_settings("tobis_stuff", "scanviewer"), + m_vecExts({ ".dat", ".DAT", ".scn", ".SCN", ".ng0", ".NG0", ".log", ".LOG" }) +{ + this->setupUi(this); + QFont font; + if(m_settings.contains("main/font_gen") && font.fromString(m_settings.value("main/font_gen", "").toString())) + setFont(font); + + splitter->setStretchFactor(0, 1); + splitter->setStretchFactor(1, 2); + + + // ------------------------------------------------------------------------- + // plot stuff + QColor colorBck(240, 240, 240, 255); + plot->setCanvasBackground(colorBck); + + m_plotwrap.reset(new QwtPlotWrapper(plot, 2, true)); + + QPen penCurve; + penCurve.setColor(QColor(0,0,0x99)); + penCurve.setWidth(2); + m_plotwrap->GetCurve(0)->setPen(penCurve); + m_plotwrap->GetCurve(0)->setStyle(QwtPlotCurve::CurveStyle::Lines); + m_plotwrap->GetCurve(0)->setTitle("Scan Curve"); + + QPen penPoints; + penPoints.setColor(QColor(0xff,0,0)); + penPoints.setWidth(4); + m_plotwrap->GetCurve(1)->setPen(penPoints); + m_plotwrap->GetCurve(1)->setStyle(QwtPlotCurve::CurveStyle::Dots); + m_plotwrap->GetCurve(1)->setTitle("Scan Points"); + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + // property map stuff + tableProps->setColumnCount(2); + tableProps->setColumnWidth(0, 150); + tableProps->setColumnWidth(1, 350); + //tableProps->sortByColumn(0); + + tableProps->setHorizontalHeaderItem(0, new QTableWidgetItem("Property")); + tableProps->setHorizontalHeaderItem(1, new QTableWidgetItem("Value")); + + tableProps->verticalHeader()->setVisible(false); + tableProps->verticalHeader()->setDefaultSectionSize(tableProps->verticalHeader()->minimumSectionSize()+4); + // ------------------------------------------------------------------------- + +#if QT_VER>=5 + ScanViewerDlg *pThis = this; + QObject::connect(editPath, &QLineEdit::textEdited, pThis, &ScanViewerDlg::ChangedPath); + QObject::connect(listFiles, &QListWidget::currentItemChanged, pThis, &ScanViewerDlg::FileSelected); + QObject::connect(btnBrowse, &QToolButton::clicked, pThis, &ScanViewerDlg::SelectDir); + QObject::connect(comboX, static_cast(&QComboBox::currentIndexChanged), pThis, &ScanViewerDlg::XAxisSelected); + QObject::connect(comboY, static_cast(&QComboBox::currentIndexChanged), pThis, &ScanViewerDlg::YAxisSelected); + QObject::connect(tableProps, &QTableWidget::currentItemChanged, pThis, &ScanViewerDlg::PropSelected); + QObject::connect(comboExport, static_cast(&QComboBox::currentIndexChanged), pThis, &ScanViewerDlg::GenerateExternal); +#else + QObject::connect(editPath, SIGNAL(textEdited(const QString&)), + this, SLOT(ChangedPath())); + //QObject::connect(listFiles, SIGNAL(itemSelectionChanged()), + // this, SLOT(FileSelected())); + QObject::connect(listFiles, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(FileSelected(QListWidgetItem*, QListWidgetItem*))); + QObject::connect(btnBrowse, SIGNAL(clicked(bool)), + this, SLOT(SelectDir())); + QObject::connect(comboX, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(XAxisSelected(const QString&))); + QObject::connect(comboY, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(YAxisSelected(const QString&))); + QObject::connect(tableProps, SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)), + this, SLOT(PropSelected(QTableWidgetItem*, QTableWidgetItem*))); + QObject::connect(comboExport, SIGNAL(currentIndexChanged(int)), + this, SLOT(GenerateExternal(int))); + //QObject::connect(btnOpenExt, SIGNAL(clicked()), this, SLOT(openExternally())); +#endif + + QString strDir = m_settings.value("last_dir", tl::wstr_to_str(fs::current_path().native()).c_str()).toString(); + editPath->setText(strDir); + + m_bDoUpdate = 1; + ChangedPath(); + + + if(m_settings.contains("geo")) + restoreGeometry(m_settings.value("geo").toByteArray()); +} + +ScanViewerDlg::~ScanViewerDlg() +{ + ClearPlot(); + tableProps->setRowCount(0); +} + +void ScanViewerDlg::closeEvent(QCloseEvent* pEvt) +{ + m_settings.setValue("geo", saveGeometry()); + QDialog::closeEvent(pEvt); +} + +void ScanViewerDlg::ClearPlot() +{ + if(m_pInstr) + { + delete m_pInstr; + m_pInstr = nullptr; + } + + m_vecX.clear(); + m_vecY.clear(); + + set_qwt_data()(*m_plotwrap, m_vecX, m_vecY, 0, 0); + set_qwt_data()(*m_plotwrap, m_vecX, m_vecY, 1, 0); + + m_strX = m_strY = m_strCmd = ""; + plot->setAxisTitle(QwtPlot::xBottom, ""); + plot->setAxisTitle(QwtPlot::yLeft, ""); + plot->setTitle(""); + + auto edits = { editA, editB, editC, + editAlpha, editBeta, editGamma, + editPlaneX0, editPlaneX1, editPlaneX2, + editPlaneY0, editPlaneY1, editPlaneY2, + editTitle, editSample, + editUser, editContact, + editKfix, editTimestamp }; + for(auto* pEdit : edits) + pEdit->setText(""); + + comboX->clear(); + comboY->clear(); + textRoot->clear(); + + m_plotwrap->GetPlot()->replot(); +} + +void ScanViewerDlg::SelectDir() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strCurDir = (m_strCurDir==""?".":m_strCurDir.c_str()); + QString strDir = QFileDialog::getExistingDirectory(this, "Select directory", + strCurDir, QFileDialog::ShowDirsOnly | fileopt); + if(strDir != "") + { + editPath->setText(strDir); + ChangedPath(); + } +} + +void ScanViewerDlg::XAxisSelected(const QString& strLab) { PlotScan(); } +void ScanViewerDlg::YAxisSelected(const QString& strLab) { PlotScan(); } + +void ScanViewerDlg::FileSelected(QListWidgetItem *pItem, QListWidgetItem *pItemPrev) +{ + //QListWidgetItem *pItem = listFiles->currentItem(); + if(!pItem) return; + + m_strCurFile = pItem->text().toStdString(); + + + ClearPlot(); + std::string strFile = m_strCurDir + m_strCurFile; + m_pInstr = tl::FileInstrBase::LoadInstr(strFile.c_str()); + if(!m_pInstr) return; + + std::vector vecScanVars = m_pInstr->GetScannedVars(); + std::string strCntVar = m_pInstr->GetCountVar(); + //std::string strMonVar = m_pInstr->GetMonVar(); + //tl::log_info("Count var: ", strCntVar, ", mon var: ", strMonVar); + + m_bDoUpdate = 0; + int iIdxX=-1, iIdxY=-1, iCurIdx=0; + const tl::FileInstrBase::t_vecColNames& vecColNames = m_pInstr->GetColNames(); + for(const tl::FileInstrBase::t_vecColNames::value_type& strCol : vecColNames) + { + comboX->addItem(strCol.c_str()); + comboY->addItem(strCol.c_str()); + + if(vecScanVars.size() && vecScanVars[0]==strCol) + iIdxX = iCurIdx; + if(strCntVar==strCol) + iIdxY = iCurIdx; + + ++iCurIdx; + } + + comboX->setCurrentIndex(iIdxX); + comboY->setCurrentIndex(iIdxY); + + m_bDoUpdate = 1; + + ShowProps(); + PlotScan(); +} + +void ScanViewerDlg::PlotScan() +{ + if(m_pInstr==nullptr || !m_bDoUpdate) + return; + + m_strX = comboX->currentText().toStdString(); + m_strY = comboY->currentText().toStdString(); + std::string strTitle = m_pInstr->GetTitle(); + m_strCmd = m_pInstr->GetScanCommand(); + + m_vecX = m_pInstr->GetCol(m_strX.c_str()); + m_vecY = m_pInstr->GetCol(m_strY.c_str()); + //tl::log_debug("Number of points: ", m_vecX.size(), ", ", m_vecY.size()); + + std::array arrLatt = m_pInstr->GetSampleLattice(); + std::array arrAng = m_pInstr->GetSampleAngles(); + std::array arrPlaneX = m_pInstr->GetScatterPlane0(); + std::array arrPlaneY = m_pInstr->GetScatterPlane1(); + + editA->setText(tl::var_to_str(arrLatt[0]).c_str()); + editB->setText(tl::var_to_str(arrLatt[1]).c_str()); + editC->setText(tl::var_to_str(arrLatt[2]).c_str()); + editAlpha->setText(tl::var_to_str(tl::r2d(arrAng[0])).c_str()); + editBeta->setText(tl::var_to_str(tl::r2d(arrAng[1])).c_str()); + editGamma->setText(tl::var_to_str(tl::r2d(arrAng[2])).c_str()); + + editPlaneX0->setText(tl::var_to_str(arrPlaneX[0]).c_str()); + editPlaneX1->setText(tl::var_to_str(arrPlaneX[1]).c_str()); + editPlaneX2->setText(tl::var_to_str(arrPlaneX[2]).c_str()); + editPlaneY0->setText(tl::var_to_str(arrPlaneY[0]).c_str()); + editPlaneY1->setText(tl::var_to_str(arrPlaneY[1]).c_str()); + editPlaneY2->setText(tl::var_to_str(arrPlaneY[2]).c_str()); + + labelKfix->setText(m_pInstr->IsKiFixed() + ? QString::fromWCharArray(L"ki (1/\x212b):") + : QString::fromWCharArray(L"kf (1/\x212b):")); + editKfix->setText(tl::var_to_str(m_pInstr->GetKFix()).c_str()); + + editTitle->setText(strTitle.c_str()); + editSample->setText(m_pInstr->GetSampleName().c_str()); + editUser->setText(m_pInstr->GetUser().c_str()); + editContact->setText(m_pInstr->GetLocalContact().c_str()); + editTimestamp->setText(m_pInstr->GetTimestamp().c_str()); + + + plot->setAxisTitle(QwtPlot::xBottom, m_strX.c_str()); + plot->setAxisTitle(QwtPlot::yLeft, m_strY.c_str()); + plot->setTitle(m_strCmd.c_str()); + + + if(m_vecX.size()==0 || m_vecY.size()==0) + return; + + set_qwt_data()(*m_plotwrap, m_vecX, m_vecY, 0, 0); + set_qwt_data()(*m_plotwrap, m_vecX, m_vecY, 1, 1); + + GenerateExternal(comboExport->currentIndex()); +} + +void ScanViewerDlg::GenerateExternal(int iLang) +{ + textRoot->clear(); + if(!m_vecX.size() || !m_vecY.size()) + return; + + if(iLang == 0) + GenerateForRoot(); + else if(iLang == 1) + GenerateForGnuplot(); + else if(iLang == 2) + GenerateForPython(); + else if(iLang == 3) + GenerateForHermelin(); + else + tl::log_err("Unknown external language."); +} + +void ScanViewerDlg::GenerateForGnuplot() +{ + const std::string& strTitle = m_strCmd; + const std::string& strLabelX = m_strX; + const std::string& strLabelY = m_strY; + + std::string strPySrc = +R"RAWSTR(set term wxt + +set xlabel "%%LABELX%%" +set ylabel "%%LABELY%%" +set title "%%TITLE%%" +set grid + +set xrange [%%MINX%%:%%MAXX%%] +set yrange [%%MINY%%:%%MAXY%%] + +plot "-" using 1:2:3 pt 7 with yerrorbars title "Data" +%%POINTS%% +end)RAWSTR"; + + + std::vector vecYErr = m_vecY; + std::for_each(vecYErr.begin(), vecYErr.end(), [](t_real& d) { d = std::sqrt(d); }); + + auto minmaxX = std::minmax_element(m_vecX.begin(), m_vecX.end()); + auto minmaxY = std::minmax_element(m_vecY.begin(), m_vecY.end()); + t_real dMaxErrY = *std::max_element(vecYErr.begin(), vecYErr.end()); + + std::ostringstream ostrPoints; + + for(std::size_t i=0; i(strPySrc, "%%MINX%%", tl::var_to_str(*minmaxX.first)); + tl::find_and_replace(strPySrc, "%%MAXX%%", tl::var_to_str(*minmaxX.second)); + tl::find_and_replace(strPySrc, "%%MINY%%", tl::var_to_str(*minmaxY.first-dMaxErrY)); + tl::find_and_replace(strPySrc, "%%MAXY%%", tl::var_to_str(*minmaxY.second+dMaxErrY)); + tl::find_and_replace(strPySrc, "%%TITLE%%", strTitle); + tl::find_and_replace(strPySrc, "%%LABELX%%", strLabelX); + tl::find_and_replace(strPySrc, "%%LABELY%%", strLabelY); + tl::find_and_replace(strPySrc, "%%POINTS%%", ostrPoints.str()); + + textRoot->setText(strPySrc.c_str()); +} + +void ScanViewerDlg::GenerateForPython() +{ + const std::string& strTitle = m_strCmd; + const std::string& strLabelX = m_strX; + const std::string& strLabelY = m_strY; + + std::string strPySrc = +R"RAWSTR(import numpy as np + +x = np.array([ %%VECX%% ]) +y = np.array([ %%VECY%% ]) +yerr = np.array([ %%VECYERR%% ]) + +min = np.array([ %%MINX%%, %%MINY%% ]) +max = np.array([ %%MAXX%%, %%MAXY%% ]) +range = max-min +mid = min + range*0.5 + +yerr = [a if a!=0. else 0.001*range[1] for a in yerr] + + + +import scipy.optimize as opt + +def gauss_model(x, x0, sigma, amp, offs): + return amp * np.exp(-0.5 * ((x-x0) / sigma)**2.) + offs + +hints = [mid[0], range[0]*0.5, range[1]*0.5, min[1]] +popt, pcov = opt.curve_fit(gauss_model, x, y, sigma=yerr, absolute_sigma=True, p0=hints) + +x_fine = np.linspace(min[0], max[0], 128) +y_fit = gauss_model(x_fine, *popt) + + + +import matplotlib.pyplot as plt + +plt.figure() + +plt.xlim(min[0], max[0]) +plt.ylim(min[1], max[1]) + +plt.title("%%TITLE%%") +plt.xlabel("%%LABELX%%") +plt.ylabel("%%LABELY%%") + +plt.grid(True) +plt.errorbar(x,y,yerr, fmt="o") +plt.plot(x_fine, y_fit) +plt.show())RAWSTR"; + + + std::vector vecYErr = m_vecY; + std::for_each(vecYErr.begin(), vecYErr.end(), [](t_real& d) { d = std::sqrt(d); }); + + auto minmaxX = std::minmax_element(m_vecX.begin(), m_vecX.end()); + auto minmaxY = std::minmax_element(m_vecY.begin(), m_vecY.end()); + t_real dMaxErrY = *std::max_element(vecYErr.begin(), vecYErr.end()); + + std::ostringstream ostrX, ostrY, ostrYErr; + + for(std::size_t i=0; i(strPySrc, "%%MINX%%", tl::var_to_str(*minmaxX.first)); + tl::find_and_replace(strPySrc, "%%MAXX%%", tl::var_to_str(*minmaxX.second)); + tl::find_and_replace(strPySrc, "%%MINY%%", tl::var_to_str(*minmaxY.first-dMaxErrY)); + tl::find_and_replace(strPySrc, "%%MAXY%%", tl::var_to_str(*minmaxY.second+dMaxErrY)); + tl::find_and_replace(strPySrc, "%%TITLE%%", strTitle); + tl::find_and_replace(strPySrc, "%%LABELX%%", strLabelX); + tl::find_and_replace(strPySrc, "%%LABELY%%", strLabelY); + tl::find_and_replace(strPySrc, "%%VECX%%", ostrX.str()); + tl::find_and_replace(strPySrc, "%%VECY%%", ostrY.str()); + tl::find_and_replace(strPySrc, "%%VECYERR%%", ostrYErr.str()); + + textRoot->setText(strPySrc.c_str()); +} + +void ScanViewerDlg::GenerateForHermelin() +{ + std::string strStoatSrc = +R"RAWSTR(#!./hermelin -t + +module_init() +{ + import("apps/instr.scr"); + + global fit_dbg = 1; + global theterm = "wxt"; + global norm_to_mon = 1; +} + +scan_plot() +{ + scanfile = "%%FILE%%"; + [instr, datx, daty, datyerr, xlab, ylab] = load_instr(scanfile, norm_to_mon); + title = "\"" + scanfile + "\""; + + maxx = max(datx); minx = min(datx); + maxy = max(daty); miny = min(daty); + rangex = maxx-minx; rangey = maxy-miny; + midx = minx + rangex*0.5; + + + gauss_pos = [midx]; + gauss_amp = [rangey*0.5]; + gauss_sig = [rangex*0.5]; + bckgrd = miny; + fitsteps = ["xxx x"]; + + outfile = ""; + #outfile = "scan_plot.pdf"; + + thefit = fit_gauss_manual_singlestep(datx, daty, datyerr, gauss_pos, gauss_amp, gauss_sig, bckgrd, fitsteps); + + + plotmap = map(); + plotmap = ["xlimits" : minx + " " + maxx]; + #plotmap += ["ylimits" : "0 0.5"]; + + plot_gausses(1, thefit, [datx, daty, datyerr], title, xlab, ylab, outfile, plotmap); +} + +main(args) +{ + scan_plot(); +})RAWSTR"; + + const std::string strFile = m_strCurDir + m_strCurFile; + tl::find_and_replace(strStoatSrc, "%%FILE%%", strFile); + + textRoot->setText(strStoatSrc.c_str()); +} + +void ScanViewerDlg::GenerateForRoot() +{ + const std::string& strTitle = m_strCmd; + const std::string& strLabelX = m_strX; + const std::string& strLabelY = m_strY; + + std::string strRootSrc = +R"RAWSTR(void scan_plot() +{ + const Double_t vecX[] = { %%VECX%% }; + const Double_t vecY[] = { %%VECY%% }; + const Double_t vecYErr[] = { %%VECYERR%% }; + + const Double_t dMin[] = { %%MINX%%, %%MINY%% }; + const Double_t dMax[] = { %%MAXX%%, %%MAXY%% }; + const Int_t iSize = sizeof(vecX)/sizeof(*vecX); + + gStyle->SetOptFit(1); + TCanvas *pCanvas = new TCanvas("canvas0", "Root Canvas", 800, 600); + pCanvas->SetGrid(1,1); + pCanvas->SetTicks(1,1); + //pCanvas->SetLogy(); + + TH1F *pFrame = pCanvas->DrawFrame(dMin[0], dMin[1], dMax[0], dMax[1], ""); + pFrame->SetTitle("%%TITLE%%"); + pFrame->SetXTitle("%%LABELX%%"); + pFrame->SetYTitle("%%LABELY%%"); + + TGraphErrors *pGraph = new TGraphErrors(iSize, vecX, vecY, 0, vecYErr); + pGraph->SetMarkerStyle(20); + pGraph->Draw("P"); +})RAWSTR"; + + + std::vector vecYErr = m_vecY; + std::for_each(vecYErr.begin(), vecYErr.end(), [](t_real& d) { d = std::sqrt(d); }); + + auto minmaxX = std::minmax_element(m_vecX.begin(), m_vecX.end()); + auto minmaxY = std::minmax_element(m_vecY.begin(), m_vecY.end()); + t_real dMaxErrY = *std::max_element(vecYErr.begin(), vecYErr.end()); + + std::ostringstream ostrX, ostrY, ostrYErr; + + for(std::size_t i=0; i(strRootSrc, "%%MINX%%", tl::var_to_str(*minmaxX.first)); + tl::find_and_replace(strRootSrc, "%%MAXX%%", tl::var_to_str(*minmaxX.second)); + tl::find_and_replace(strRootSrc, "%%MINY%%", tl::var_to_str(*minmaxY.first-dMaxErrY)); + tl::find_and_replace(strRootSrc, "%%MAXY%%", tl::var_to_str(*minmaxY.second+dMaxErrY)); + tl::find_and_replace(strRootSrc, "%%TITLE%%", strTitle); + tl::find_and_replace(strRootSrc, "%%LABELX%%", strLabelX); + tl::find_and_replace(strRootSrc, "%%LABELY%%", strLabelY); + tl::find_and_replace(strRootSrc, "%%VECX%%", ostrX.str()); + tl::find_and_replace(strRootSrc, "%%VECY%%", ostrY.str()); + tl::find_and_replace(strRootSrc, "%%VECYERR%%", ostrYErr.str()); + + textRoot->setText(strRootSrc.c_str()); +} + +void ScanViewerDlg::PropSelected(QTableWidgetItem *pItem, QTableWidgetItem *pItemPrev) +{ + if(!pItem) + m_strSelectedKey = ""; + + for(int iItem=0; iItemrowCount(); ++iItem) + { + const QTableWidgetItem *pKey = tableProps->item(iItem, 0); + const QTableWidgetItem *pVal = tableProps->item(iItem, 1); + + if(pKey==pItem || pVal==pItem) + { + m_strSelectedKey = pKey->text().toStdString(); + break; + } + } +} + +void ScanViewerDlg::ShowProps() +{ + if(m_pInstr==nullptr || !m_bDoUpdate) + return; + + const tl::FileInstrBase::t_mapParams& params = m_pInstr->GetAllParams(); + tableProps->setRowCount(params.size()); + + const bool bSort = tableProps->isSortingEnabled(); + tableProps->setSortingEnabled(0); + unsigned int iItem = 0; + for(const tl::FileInstrBase::t_mapParams::value_type& pair : params) + { + QTableWidgetItem *pItemKey = tableProps->item(iItem, 0); + if(!pItemKey) + { + pItemKey = new QTableWidgetItem(); + tableProps->setItem(iItem, 0, pItemKey); + } + + QTableWidgetItem* pItemVal = tableProps->item(iItem, 1); + if(!pItemVal) + { + pItemVal = new QTableWidgetItem(); + tableProps->setItem(iItem, 1, pItemVal); + } + + pItemKey->setText(pair.first.c_str()); + pItemVal->setText(pair.second.c_str()); + + ++iItem; + } + + tableProps->setSortingEnabled(bSort); + //tableProps->sortItems(0, Qt::AscendingOrder); + + + // retain previous selection + bool bHasSelection = 0; + for(int iItem=0; iItemrowCount(); ++iItem) + { + const QTableWidgetItem *pItem = tableProps->item(iItem, 0); + if(!pItem) continue; + + if(pItem->text().toStdString() == m_strSelectedKey) + { + tableProps->selectRow(iItem); + bHasSelection = 1; + break; + } + } + + if(!bHasSelection) + tableProps->selectRow(0); +} + +void ScanViewerDlg::ChangedPath() +{ + listFiles->clear(); + ClearPlot(); + tableProps->setRowCount(0); + + std::string strPath = editPath->text().toStdString(); + fs::path dir(strPath); + if(fs::exists(dir) && fs::is_directory(dir)) + { + m_strCurDir = tl::wstr_to_str(dir.native()); + tl::trim(m_strCurDir); + if(*(m_strCurDir.begin()+m_strCurDir.length()-1) != fs::path::preferred_separator) + m_strCurDir += fs::path::preferred_separator; + UpdateFileList(); + + m_settings.setValue("last_dir", QString(m_strCurDir.c_str())); + } +} + +void ScanViewerDlg::UpdateFileList() +{ + listFiles->clear(); + + try + { + fs::path dir(m_strCurDir); + fs::directory_iterator dir_begin(dir), dir_end; + + std::set lst; + std::copy_if(dir_begin, dir_end, std::insert_iterator(lst, lst.end()), + [this](const fs::path& p) -> bool + { + std::string strExt = tl::wstr_to_str(p.extension().native()); + if(strExt == ".bz2" || strExt == ".gz" || strExt == ".z") + strExt = "." + tl::wstr_to_str(tl::get_fileext2(p.filename().native())); + + if(this->m_vecExts.size() == 0) + return true; + return std::find(this->m_vecExts.begin(), this->m_vecExts.end(), + strExt) != this->m_vecExts.end(); + }); + + for(const fs::path& d : lst) + listFiles->addItem(tl::wstr_to_str(d.filename().native()).c_str()); + } + catch(const std::exception& ex) + {} +} + +#include "scanviewer.moc" diff --git a/tools/scanviewer/scanviewer.h b/tools/scanviewer/scanviewer.h new file mode 100644 index 0000000..3ef9616 --- /dev/null +++ b/tools/scanviewer/scanviewer.h @@ -0,0 +1,69 @@ +/* + * Scan viewer + * @author tweber + * @date mar-2015 + * @license GPLv2 + */ + +#ifndef __TAZ_SCANVIEWER_H__ +#define __TAZ_SCANVIEWER_H__ + +#include +#include +#include +#include +#include + +#include "tlibs/file/loadinstr.h" +#include "libs/qthelper.h" +#include "libs/globals.h" +#include "ui/ui_scanviewer.h" + + +class ScanViewerDlg : public QDialog, Ui::ScanViewerDlg +{ Q_OBJECT +protected: + QSettings m_settings; + std::string m_strCurDir, m_strCurFile; + std::string m_strSelectedKey; + std::vector m_vecExts; + + bool m_bDoUpdate = 0; + tl::FileInstrBase *m_pInstr = nullptr; + std::vector m_vecX, m_vecY; + std::unique_ptr m_plotwrap; + std::string m_strX, m_strY, m_strCmd; + +protected: + void ClearPlot(); + void PlotScan(); + void ShowProps(); + + void GenerateForRoot(); + void GenerateForGnuplot(); + void GenerateForPython(); + void GenerateForHermelin(); + + virtual void closeEvent(QCloseEvent* pEvt) override; + +protected slots: + void GenerateExternal(int iLang=0); + + void UpdateFileList(); + void FileSelected(QListWidgetItem *pItem, QListWidgetItem *pItemPrev); + void PropSelected(QTableWidgetItem *pItem, QTableWidgetItem *pItemPrev); + void SelectDir(); + void ChangedPath(); + + void XAxisSelected(const QString&); + void YAxisSelected(const QString&); + + //void openExternally(); + +public: + ScanViewerDlg(QWidget* pParent = nullptr); + virtual ~ScanViewerDlg(); +}; + + +#endif diff --git a/tools/sggen/domains.cpp b/tools/sggen/domains.cpp new file mode 100644 index 0000000..37d8604 --- /dev/null +++ b/tools/sggen/domains.cpp @@ -0,0 +1,88 @@ +// gcc -o domains domains.cpp -std=c++11 -lstdc++ -lm -I../.. -I/usr/include/QtGui/ ../../helper/spacegroup_clp.cpp ../../helper/crystalsys.cpp -DNO_QT -lclipper-core ../../tlibs/log/log.cpp + +/** + * generates positions based on space group + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include "tlibs/math/linalg.h" +#include "tlibs/math/linalg_ops.h" +#include "tlibs/string/string.h" +#include "libs/spacegroups/spacegroup_clp.h" + + +typedef tl::ublas::vector t_vec; +typedef tl::ublas::matrix t_mat; + +void gen_dirs() +{ + std::string strSg; + std::cout << "Enter spacegroup: "; + std::getline(std::cin, strSg); + tl::trim(strSg); + clipper::Spgr_descr dsc(strSg); + + const int iSGNum = dsc.spacegroup_number(); + if(iSGNum <= 0) + { + std::cerr << "Error: Unknown spacegroup." << std::endl; + return; + } + std::cout << "Spacegroup number: " << iSGNum << std::endl; + + + clipper::Spacegroup sg(dsc); + std::vector vecTrafos; + get_symtrafos(sg, vecTrafos); + std::cout << vecTrafos.size() << " symmetry operations." << std::endl; + + + t_vec vecDir(4); + std::cout << "Enter direction: "; + std::cin >> vecDir[0] >> vecDir[1] >> vecDir[2]; + vecDir[3] = 0.; // no translations, only point groups + + + std::vector vecNewDirs; + std::cout << "\nall transformations:" << std::endl; + for(const t_mat& matTrafo : vecTrafos) + { + t_vec vecDirNew = ublas::prod(matTrafo, vecDir); + std::cout << vecDirNew << " (from trafo " << matTrafo << ")" << std::endl; + + bool bHasDir = 0; + for(const t_vec& vec : vecNewDirs) + if(tl::vec_equal(vec, vecDirNew)) + { + bHasDir = 1; + break; + } + if(!bHasDir) + vecNewDirs.push_back(vecDirNew); + } + + std::cout << "\nunique transformations:" << std::endl; + for(const t_vec& vec : vecNewDirs) + { + std::cout << vec << std::endl; + } +} + + +int main() +{ + try + { + gen_dirs(); + } + catch(const clipper::Message_fatal& err) + { + std::cerr << "Error in spacegroup." << std::endl; + } + return 0; +} diff --git a/tools/sggen/sfact.cpp b/tools/sggen/sfact.cpp new file mode 100644 index 0000000..c5c18ea --- /dev/null +++ b/tools/sggen/sfact.cpp @@ -0,0 +1,220 @@ +// gcc -o sfact sfact.cpp -std=c++11 -lstdc++ -lm -I../.. -I/usr/include/QtGui/ ../../helper/spacegroup_clp.cpp ../../helper/crystalsys.cpp ../../helper/globals.cpp ../../helper/formfact.cpp ../../tlibs/log/log.cpp -DNO_QT -lclipper-core -lboost_system -lboost_filesystem +/** + * generates structure factors + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include "tlibs/math/atoms.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/linalg_ops.h" +#include "tlibs/string/string.h" +#include "libs/spacegroups/spacegroup_clp.h" +#include "libs/formfactors/formfact.h" +#include "libs/globals.h" + + +using t_real = t_real_glob; +typedef tl::ublas::vector t_vec; +typedef tl::ublas::matrix t_mat; + +void gen_atoms_sfact() +{ + std::shared_ptr> lst = ScatlenList::GetInstance(); + std::shared_ptr> lstff = FormfactList::GetInstance(); + + + t_real a,b,c, alpha,beta,gamma; + std::cout << "Enter unit cell lattice constants: "; + std::cin >> a >> b >> c; + std::cout << "Enter unit cell angles: "; + std::cin >> alpha >> beta >> gamma; + + alpha = tl::d2r(alpha); + beta = tl::d2r(beta); + gamma = tl::d2r(gamma); + + const tl::Lattice lattice(a,b,c, alpha,beta,gamma); + const t_real dVol = lattice.GetVol(); + const t_mat matA = lattice.GetMetric(); + const t_mat matB = lattice.GetRecip().GetMetric(); + std::cout << "A = " << matA << std::endl; + std::cout << "B = " << matB << std::endl; + + + + std::cout << std::endl; + std::string strSg; + std::cout << "Enter spacegroup: "; + std::cin.ignore(); + std::getline(std::cin, strSg); + clipper::Spgr_descr dsc(strSg); + const int iSGNum = dsc.spacegroup_number(); + if(iSGNum <= 0) + { + std::cerr << "Error: Unknown spacegroup." << std::endl; + return; + } + std::cout << "Spacegroup number: " << iSGNum << std::endl; + + + + std::cout << std::endl; + int iAtom=0; + std::vector vecElems; + std::vector vecAtoms; + while(1) + { + std::cout << "Enter element " << (++iAtom) << " name (or to finish): "; + std::string strElem; + std::getline(std::cin, strElem); + tl::trim(strElem); + if(strElem == "") + break; + + std::cout << "Enter atom position " << (iAtom) << ": "; + std::string strAtom; + std::getline(std::cin, strAtom); + tl::trim(strAtom); + if(strAtom == "") + break; + + + vecElems.push_back(strElem); + + t_vec vec(4); + std::istringstream istrAtom(strAtom); + istrAtom >> vec[0] >> vec[1] >> vec[2]; + vec[3] = 1.; + vecAtoms.push_back(vec); + } + + + + clipper::Spacegroup sg(dsc); + std::vector vecTrafos; + get_symtrafos(sg, vecTrafos); + std::cout << vecTrafos.size() << " symmetry operations in spacegroup." << std::endl; + + std::vector vecNumAtoms; + std::vector vecAllAtoms; + std::vector> vecScatlens; + std::vector vecFormfacts; + std::vector vecAtomIndices; + + t_real dSigAbs = 0.; + + for(int iAtom=0; iAtom vecPos = tl::generate_atoms(vecTrafos, vecAtom); + vecNumAtoms.push_back(vecPos.size()); + std::cout << "Generated " << vecPos.size() << " " << vecElems[iAtom] << " atoms." << std::endl; + for(const t_vec& vec : vecPos) + std::cout << vec << std::endl; + + const ScatlenList::elem_type* pElem = lst->Find(vecElems[iAtom]); + + if(pElem == nullptr) + { + std::cerr << "Error: cannot get scattering length for " + << vecElems[iAtom] << "." << std::endl; + return; + } + + std::complex b = pElem->GetCoherent() /*/ 10.*/; + + dSigAbs += tl::macro_xsect(pElem->GetXSecCoherent().real()*tl::get_one_barn(), + vecNumAtoms[iAtom], + dVol*tl::get_one_angstrom()*tl::get_one_angstrom()*tl::get_one_angstrom()) * tl::get_one_centimeter(); + //dSigAbs += pElem->GetXSecCoherent().real()*1e-24 * vecNumAtoms[iAtom] / (dVol*1e-24); + + for(t_vec vecThisAtom : vecPos) + { + vecThisAtom.resize(3,1); + vecAllAtoms.push_back(tl::mult(matA, vecThisAtom)); + vecScatlens.push_back(b); + vecAtomIndices.push_back(iAtom); + } + } + + const t_real dLam0 = 1.8; // thermal + const t_real dLam = 4.5; + std::cout << "\nMacroscopic absorption cross-section for lambda = 4.5 A: " + << dSigAbs*dLam/dLam0 << " / cm." << std::endl; + + //for(const t_vec& vecAt : vecAllAtoms) std::cout << vecAt << std::endl; + //for(const std::complex& cb : vecScatlens) std::cout << cb << std::endl; + + + while(1) + { + std::cout << std::endl; + + t_real h=0., k=0., l=0.; + std::cout << "Enter hkl: "; + std::cin >> h >> k >> l; + + t_vec vecG = tl::mult(matB, tl::make_vec({h,k,l})); + t_real dG = ublas::norm_2(vecG); + std::cout << "G = " << dG << " / A" << std::endl; + + + vecFormfacts.clear(); + for(unsigned int iAtom=0; iAtom::elem_type* pElemff = lstff->Find(vecElems[vecAtomIndices[iAtom]]); + + if(pElemff == nullptr) + { + std::cerr << "Error: cannot get form factor for " + << vecElems[iAtom] << "." << std::endl; + return; + } + + t_real dFF = pElemff->GetFormfact(dG); + vecFormfacts.push_back(dFF); + } + + + std::complex F = tl::structfact, ublas::vector, std::vector> + (vecAllAtoms, vecG, vecScatlens); + std::complex Fx = tl::structfact, std::vector> + (vecAllAtoms, vecG, vecFormfacts); + + + std::cout << std::endl; + std::cout << "Neutron structure factor: " << std::endl; + t_real dFsq = (std::conj(F)*F).real(); + std::cout << "F = " << F << std::endl; + std::cout << "|F| = " << std::sqrt(dFsq) << std::endl; + std::cout << "|F|^2 = " << dFsq << std::endl; + + std::cout << std::endl; + std::cout << "X-ray structure factor: " << std::endl; + t_real dFxsq = (std::conj(Fx)*Fx).real(); + std::cout << "Fx = " << Fx << std::endl; + std::cout << "|Fx| = " << std::sqrt(dFxsq) << std::endl; + std::cout << "|Fx|^2 = " << dFxsq << std::endl; + } +} + + +int main() +{ + try + { + gen_atoms_sfact(); + } + catch(const clipper::Message_fatal& err) + { + std::cerr << "Error in spacegroup." << std::endl; + } + return 0; +} diff --git a/tools/sggen/sggen.cpp b/tools/sggen/sggen.cpp new file mode 100644 index 0000000..17c3a36 --- /dev/null +++ b/tools/sggen/sggen.cpp @@ -0,0 +1,166 @@ +// gcc -o sggen sggen.cpp -std=c++11 -lstdc++ -lm -I../.. -I/usr/include/QtGui/ ../../helper/spacegroup_clp.cpp ../../helper/crystalsys.cpp -DNO_QT -lclipper-core ../../tlibs/file/x3d.cpp ../../tlibs/log/log.cpp + +/** + * generates atom positions based on space group + * @author tweber + * @date nov-2015 + * @license GPLv2 + */ + +#include +#include +#include +#include "tlibs/math/atoms.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/linalg_ops.h" +#include "tlibs/file/x3d.h" +#include "tlibs/string/string.h" +#include "libs/spacegroups/spacegroup_clp.h" + + +typedef tl::ublas::vector t_vec; +typedef tl::ublas::matrix t_mat; + +void gen_atoms() +{ + const std::vector vecColors = + { + tl::make_vec({1., 0., 0.}), + tl::make_vec({0., 1., 0.}), + tl::make_vec({0., 0., 1.}), + tl::make_vec({1., 1., 0.}), + tl::make_vec({0., 1., 1.}), + tl::make_vec({1., 0., 1.}), + }; + + // to transform into program-specific coordinate systems + const t_mat matGlobal = tl::make_mat( + { {-1., 0., 0., 0.}, + { 0., 0., 1., 0.}, + { 0., 1., 0., 0.}, + { 0., 0., 0., 1.} }); + + + double a,b,c, alpha,beta,gamma; + std::cout << "Enter unit cell lattice constants: "; + std::cin >> a >> b >> c; + std::cout << "Enter unit cell angles: "; + std::cin >> alpha >> beta >> gamma; + + alpha = tl::d2r(alpha); + beta = tl::d2r(beta); + gamma = tl::d2r(gamma); + + const tl::Lattice lattice(a,b,c, alpha,beta,gamma); + const t_mat matA = lattice.GetMetric(); + + + std::string strSg; + + std::cout << "Enter spacegroup: "; + std::cin.ignore(); + std::getline(std::cin, strSg); + clipper::Spgr_descr dsc(strSg); + const int iSGNum = dsc.spacegroup_number(); + if(iSGNum <= 0) + { + std::cerr << "Error: Unknown spacegroup." << std::endl; + return; + } + std::cout << "Spacegroup number: " << iSGNum << std::endl; + + + + int iAtom=0; + std::vector vecAtoms; + while(1) + { + std::cout << "Enter atom position " << (++iAtom) << ": "; + std::string strAtom; + std::getline(std::cin, strAtom); + tl::trim(strAtom); + if(strAtom == "") + break; + + t_vec vec(4); + std::istringstream istrAtom(strAtom); + istrAtom >> vec[0] >> vec[1] >> vec[2]; + vec[3] = 1.; + vecAtoms.push_back(vec); + } + + + + clipper::Spacegroup sg(dsc); + std::vector vecTrafos; + get_symtrafos(sg, vecTrafos); + + + + tl::X3d x3d; + + std::cout << std::endl; + //const t_vec vecOffs = tl::make_vec({0.5, 0.5, 0.5, 0.}); + for(int iAtom=0; iAtom vecPos = tl::generate_atoms(vecTrafos, vecAtom); + + std::cout << "Atom " << (iAtom+1) << ":\n"; + for(int iPos=0; iPos dUCSize*0.5) + vecCoord[iComp] -= dUCSize; + while(vecCoord[iComp] < -dUCSize*0.5) + vecCoord[iComp] += dUCSize; + } + std::cout << "\t(" << (iPos+1) << ") " << vecCoord << "\n"; + + vecCoord.resize(3,1); + vecCoord = matA * vecCoord; + vecCoord.resize(4,1); vecCoord[3] = 1.; + + tl::X3dTrafo *pTrafo = new tl::X3dTrafo(); + pTrafo->SetTrans(matGlobal * vecCoord); + tl::X3dSphere *pSphere = new tl::X3dSphere(0.1); + pSphere->SetColor(vecColors[iAtom % vecColors.size()]); + pTrafo->AddChild(pSphere); + + x3d.GetScene().AddChild(pTrafo); + } + std::cout << std::endl; + } + + + // test: only for cubic unit cells! + tl::X3dCube *pCube = new tl::X3dCube(a,b,c); + pCube->SetColor(tl::make_vec({1., 1., 1., 0.75})); + x3d.GetScene().AddChild(pCube); + + if(x3d.Save("out.x3d")) + std::cout << "Wrote out.x3d." << std::endl; +} + + +int main() +{ + try + { + gen_atoms(); + } + catch(const clipper::Message_fatal& err) + { + std::cerr << "Error in spacegroup." << std::endl; + } + return 0; +} diff --git a/tools/sglist/SgListDlg.cpp b/tools/sglist/SgListDlg.cpp new file mode 100644 index 0000000..e4386c3 --- /dev/null +++ b/tools/sglist/SgListDlg.cpp @@ -0,0 +1,292 @@ +/* + * Space Group List Dialog + * @author tweber + * @date oct-2015 + * @license GPLv2 + */ + +#include "SgListDlg.h" +#include +//#include +#include "tlibs/string/string.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/globals.h" + +using t_real = t_real_glob; + + +SgListDlg::SgListDlg(QWidget *pParent) + : QDialog(pParent, Qt::WindowTitleHint|Qt::WindowCloseButtonHint|Qt::WindowMinMaxButtonsHint), + m_settings("tobis_stuff", "sglist") +{ + setupUi(this); + QFont font; + if(m_settings.contains("main/font_gen") && font.fromString(m_settings.value("main/font_gen", "").toString())) + setFont(font); + + + SetupSpacegroups(); + + QObject::connect(listSGs, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(SGSelected(QListWidgetItem*, QListWidgetItem*))); + QObject::connect(checkMatrices, SIGNAL(toggled(bool)), this, SLOT(UpdateSG())); + + for(QSpinBox* pSpin : {spinH, spinK, spinL}) + QObject::connect(pSpin, SIGNAL(valueChanged(int)), this, SLOT(RecalcBragg())); + + for(QDoubleSpinBox* pSpin : {spinX, spinY, spinZ, spinW}) + QObject::connect(pSpin, SIGNAL(valueChanged(double)), this, SLOT(CalcTrafo())); + + QObject::connect(editFilter, SIGNAL(textEdited(const QString&)), + this, SLOT(SearchSG(const QString&))); + + + if(m_settings.contains("sglist/geo")) + restoreGeometry(m_settings.value("sglist/geo").toByteArray()); +} + +SgListDlg::~SgListDlg() +{} + +void SgListDlg::closeEvent(QCloseEvent* pEvt) +{ + m_settings.setValue("sglist/geo", saveGeometry()); +} + + +static QListWidgetItem* create_header_item(const char *pcTitle) +{ + QListWidgetItem *pHeaderItem = new QListWidgetItem(pcTitle); + pHeaderItem->setTextAlignment(Qt::AlignHCenter); + + QFont fontHeader = pHeaderItem->font(); + fontHeader.setBold(1); + pHeaderItem->setFont(fontHeader); + + QBrush brushHeader = pHeaderItem->foreground(); + brushHeader.setColor(QColor(0xff, 0xff, 0xff)); + pHeaderItem->setForeground(brushHeader); + + pHeaderItem->setData(Qt::UserRole, 1000); + pHeaderItem->setBackgroundColor(QColor(0x65, 0x65, 0x65)); + + return pHeaderItem; +} + +void SgListDlg::SetupSpacegroups() +{ + listSGs->clear(); + + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + const SpaceGroups::t_vecSpaceGroups* pvecSG = sgs->get_space_groups_vec(); + + // actually: space group TYPE, not space group... + for(unsigned int iSG=0; iSGsize(); ++iSG) + { + const SpaceGroup* psg = pvecSG->at(iSG); + unsigned int iSgNr = psg->GetNr(); + + // list headers + if(iSgNr==1) listSGs->addItem(create_header_item("Triclinic")); + else if(iSgNr==3) listSGs->addItem(create_header_item("Monoclinic")); + else if(iSgNr==16) listSGs->addItem(create_header_item("Orthorhombic")); + else if(iSgNr==75) listSGs->addItem(create_header_item("Tetragonal")); + else if(iSgNr==143) listSGs->addItem(create_header_item("Trigonal")); + else if(iSgNr==168) listSGs->addItem(create_header_item("Hexagonal")); + else if(iSgNr==195) listSGs->addItem(create_header_item("Cubic")); + + + std::ostringstream ostrSg; + ostrSg << "No. " << iSgNr << ": " << psg->GetName(); + + QListWidgetItem* pItem = new QListWidgetItem(ostrSg.str().c_str()); + pItem->setData(Qt::UserRole, iSG); + listSGs->addItem(pItem); + } +} + +void SgListDlg::UpdateSG() +{ + SGSelected(listSGs->currentItem(), nullptr); +} + +void SgListDlg::SGSelected(QListWidgetItem *pItem, QListWidgetItem*) +{ + listSymOps->clear(); + listTrafo->clear(); + for(QLineEdit *pEdit : {editHM, /*editHall,*/ editLaue, editNr/*, editAxisSym*/}) + pEdit->setText(""); + if(!pItem) return; + + + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + const SpaceGroups::t_vecSpaceGroups* pvecSG = sgs->get_space_groups_vec(); + + // header selected? + unsigned int iSG = pItem->data(Qt::UserRole).toUInt(); + if(iSG >= pvecSG->size()) + return; + + const SpaceGroup* psg = pvecSG->at(iSG); + unsigned int iSgNr = psg->GetNr(); + + const std::string& strHM = psg->GetName(); + const std::string& strPointGroup = psg->GetPointGroup(); + const std::string& strLaue = psg->GetLaueGroup(); + const std::string& strCrysSys = psg->GetCrystalSystemName(); + + editNr->setText(tl::var_to_str(iSgNr).c_str()); + editHM->setText(strHM.c_str()); + //editHall->setText(psg.symbol_hall().c_str()); + editLaue->setText(("PG: " + strPointGroup + ", LG: " + strLaue + + " (" + strCrysSys + ")").c_str()); + + bool bShowMatrices = checkMatrices->isChecked(); + + // all trafos + const std::vector::t_mat>& vecTrafos = psg->GetTrafos(); + { + std::ostringstream ostr; + ostr << "All Symmetry Operations (" << vecTrafos.size() << ")"; + listSymOps->addItem(create_header_item(ostr.str().c_str())); + + for(unsigned int iSymOp=0; iSymOpaddItem(print_matrix(vecTrafos[iSymOp]).c_str()); + else + listSymOps->addItem(get_trafo_desc(vecTrafos[iSymOp]).c_str()); + } + } + + + // primitive trafos + const std::vector& vecPrim = psg->GetPrimTrafos(); + + if(vecPrim.size()) + { + std::ostringstream ostr; + ostr << "Primitive Symmetry Operations (" << (vecPrim.size()) << ")"; + listSymOps->addItem(create_header_item(ostr.str().c_str())); + for(unsigned int iSymOp=0; iSymOpaddItem(print_matrix(vecTrafos[vecPrim[iSymOp]]).c_str()); + else + listSymOps->addItem(get_trafo_desc(vecTrafos[vecPrim[iSymOp]]).c_str()); + } + } + + + // inverting trafos + const std::vector& vecInv = psg->GetInvTrafos(); + + if(vecInv.size()) + { + std::ostringstream ostr; + ostr << "Inverting Symmetry Operations (" << (vecInv.size()) << ")"; + listSymOps->addItem(create_header_item(ostr.str().c_str())); + for(unsigned int iSymOp=0; iSymOpaddItem(print_matrix(vecTrafos[vecInv[iSymOp]]).c_str()); + else + listSymOps->addItem(get_trafo_desc(vecTrafos[vecInv[iSymOp]]).c_str()); + } + } + + // centering trafos + const std::vector& vecCenter = psg->GetCenterTrafos(); + + if(vecCenter.size()) + { + std::ostringstream ostr; + ostr << "Centering Symmetry Operations (" << (vecCenter.size()) << ")"; + listSymOps->addItem(create_header_item(ostr.str().c_str())); + for(unsigned int iSymOp=0; iSymOpaddItem(print_matrix(vecTrafos[vecCenter[iSymOp]]).c_str()); + else + listSymOps->addItem(get_trafo_desc(vecTrafos[vecCenter[iSymOp]]).c_str()); + } + } + + + RecalcBragg(); + CalcTrafo(); +} + +void SgListDlg::RecalcBragg() +{ + const QListWidgetItem* pItem = listSGs->currentItem(); + if(!pItem) return; + + const int h = spinH->value(); + const int k = spinK->value(); + const int l = spinL->value(); + + //std::cout << h << k << l << std::endl; + + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + const SpaceGroups::t_vecSpaceGroups* pvecSG = sgs->get_space_groups_vec(); + const unsigned int iSG = pItem->data(Qt::UserRole).toUInt(); + if(iSG >= pvecSG->size()) + return; + + const SpaceGroup* psg = pvecSG->at(iSG); + const bool bForbidden = !psg->HasReflection(h,k,l);; + + QFont font = spinH->font(); + font.setStrikeOut(bForbidden); + for(QSpinBox* pSpin : {spinH, spinK, spinL}) + pSpin->setFont(font); +} + +void SgListDlg::SearchSG(const QString& qstr) +{ + QList lstItems = listSGs->findItems(qstr, Qt::MatchContains); + if(lstItems.size()) + listSGs->setCurrentItem(lstItems[0], QItemSelectionModel::SelectCurrent); +} + + +void SgListDlg::CalcTrafo() +{ + listTrafo->clear(); + + const QListWidgetItem* pItem = listSGs->currentItem(); + if(!pItem) + return; + + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + const SpaceGroups::t_vecSpaceGroups* pvecSG = sgs->get_space_groups_vec(); + const unsigned int iSG = pItem->data(Qt::UserRole).toUInt(); + if(iSG >= pvecSG->size()) + return; + const SpaceGroup* psg = pvecSG->at(iSG); + + SpaceGroup::t_vec vecIn = + tl::make_vec({spinX->value(), spinY->value(), spinZ->value(), spinW->value()}); + + const std::vector::t_mat>& vecTrafos = psg->GetTrafos(); + std::vector::t_vec> vecUnique; + + listTrafo->addItem(create_header_item("All Transformation Results")); + for(const SpaceGroup::t_mat& mat : vecTrafos) + { + SpaceGroup::t_vec vec = ublas::prod(mat, vecIn); + listTrafo->addItem(print_vector(vec).c_str()); + + if(!is_vec_in_container::t_vec>(vecUnique, vec)) + vecUnique.push_back(vec); + } + + listTrafo->addItem(create_header_item("Unique Transformation Results")); + for(const SpaceGroup::t_vec& vec : vecUnique) + { + listTrafo->addItem(print_vector(vec).c_str()); + } +} + +#include "SgListDlg.moc" diff --git a/tools/sglist/SgListDlg.h b/tools/sglist/SgListDlg.h new file mode 100644 index 0000000..35ea523 --- /dev/null +++ b/tools/sglist/SgListDlg.h @@ -0,0 +1,40 @@ +/* + * Space Group List Dialog + * @author tweber + * @date oct-2015 + * @license GPLv2 + */ + +#ifndef __TAZ_SGLISTDLG_H__ +#define __TAZ_SGLISTDLG_H__ + +#include +#include + +#include "ui/ui_sglist.h" + + +class SgListDlg : public QDialog, Ui::SgListDlg +{ Q_OBJECT +protected: + QSettings m_settings; + +protected: + void SetupSpacegroups(); + virtual void closeEvent(QCloseEvent* pEvt) override; + +protected slots: + void UpdateSG(); + void SGSelected(QListWidgetItem *pItem, QListWidgetItem *pItemPrev); + void RecalcBragg(); + void SearchSG(const QString& qstr); + + void CalcTrafo(); + +public: + SgListDlg(QWidget* pParent = nullptr); + virtual ~SgListDlg(); +}; + + +#endif diff --git a/tools/sglist/main.cpp b/tools/sglist/main.cpp new file mode 100644 index 0000000..5885725 --- /dev/null +++ b/tools/sglist/main.cpp @@ -0,0 +1,29 @@ +/* + * SG-List + * @author tweber + * @date oct-2015 + * @copyright GPLv2 + */ + +#include +#include +#include +#include +#include "SgListDlg.h" +#include "libs/spacegroups/spacegroup.h" + + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + std::setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::English); + + SgListDlg dlg(0); + dlg.setWindowFlags(Qt::Window); + dlg.show(); + + int iRet = app.exec(); + return iRet; +} diff --git a/tools/taz/net.h b/tools/taz/net.h new file mode 100644 index 0000000..0f8e18f --- /dev/null +++ b/tools/taz/net.h @@ -0,0 +1,40 @@ +/* + * Interface for connections to instruments + * @author tweber + * @date mar-2016 + * @license GPLv2 + */ + +#ifndef __TAKIN_NET_IF_H__ +#define __TAKIN_NET_IF_H__ + +#include +#include +#include + +#include "tasoptions.h" +#include "dialogs/NetCacheDlg.h" + + +class NetCache : public QObject +{ Q_OBJECT + public: + virtual ~NetCache() {}; + + virtual void connect(const std::string& strHost, const std::string& strPort, + const std::string& strUser, const std::string& strPass) = 0; + virtual void disconnect() = 0; + + virtual void refresh() = 0; + + signals: + void connected(const QString& strHost, const QString& strSrv); + void disconnected(); + + void vars_changed(const CrystalOptions& crys, const TriangleOptions& triag); + + void updated_cache_value(const std::string& strKey, const CacheVal& val); + void cleared_cache(); +}; + +#endif diff --git a/tools/taz/nicos.cpp b/tools/taz/nicos.cpp new file mode 100644 index 0000000..851d8e8 --- /dev/null +++ b/tools/taz/nicos.cpp @@ -0,0 +1,302 @@ +/* + * Connection to Nicos + * @author tweber + * @date 27-aug-2014 + * @license GPLv2 + */ + +#include "nicos.h" +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#include "tlibs/helper/py.h" +#include "libs/globals.h" + +using t_real = t_real_glob; + + +NicosCache::NicosCache(QSettings* pSettings) : m_pSettings(pSettings) +{ + std::vector> vecStrings = + { + {"sample_name", &m_strSampleName}, + {"lattice", &m_strSampleLattice}, + {"angles", &m_strSampleAngles}, + {"orient1", &m_strSampleOrient1}, + {"orient2", &m_strSampleOrient2}, + {"spacegroup", &m_strSampleSpacegroup}, + {"psi0", &m_strSamplePsi0}, + {"stheta", &m_strSampleTheta}, + {"s2theta", &m_strSample2Theta}, + {"mtheta", &m_strMonoTheta}, + {"m2theta", &m_strMono2Theta}, + {"mono_d", &m_strMonoD}, + {"atheta", &m_strAnaTheta}, + {"a2theta", &m_strAna2Theta}, + {"ana_d", &m_strAnaD}, + //{"stheta_aux", &m_strSampleTheta_aux}, + //{"stheta_aux_alias", &m_strSampleTheta_aux_alias} + }; + + for(const std::pair& pair : vecStrings) + { + std::string strKey = std::string("net/") + pair.first; + if(!m_pSettings->contains(strKey.c_str())) + continue; + + *pair.second = m_pSettings->value(strKey.c_str(), pair.second->c_str()). + toString().toStdString(); + } + + m_bFlipOrient2 = m_pSettings->value("net/flip_orient2", true).toBool(); + //tl::log_info("Flipping Nicos' orientation vector 2: ", m_bFlipOrient2); + + + m_vecKeys = std::vector + { + m_strSampleName, + m_strSampleLattice, m_strSampleAngles, + m_strSampleOrient1, m_strSampleOrient2, + m_strSampleSpacegroup, + m_strSamplePsi0, m_strSampleTheta, m_strSample2Theta, + + m_strMonoD, m_strMonoTheta, m_strMono2Theta, + m_strAnaD, m_strAnaTheta, m_strAna2Theta, + + //m_strSampleTheta_aux, m_strSampleTheta_aux_alias, + + // additional info fields (not needed for calculation) + "logbook/remark", + //"nicos/ctr1/value", + "nicos/timer/value", + "nicos/timer/preselection", + }; + + m_tcp.add_connect(boost::bind(&NicosCache::slot_connected, this, _1, _2)); + m_tcp.add_disconnect(boost::bind(&NicosCache::slot_disconnected, this, _1, _2)); + m_tcp.add_receiver(boost::bind(&NicosCache::slot_receive, this, _1)); +} + +NicosCache::~NicosCache() +{ + disconnect(); +} + +void NicosCache::connect(const std::string& strHost, const std::string& strPort, + const std::string& strUser, const std::string& strPass) +{ + m_mapCache.clear(); + emit cleared_cache(); + + if(!m_tcp.connect(strHost, strPort)) + return; +} + +void NicosCache::disconnect() +{ + m_tcp.disconnect(); +} + +void NicosCache::refresh() +{ + RefreshKeys(); +} + +void NicosCache::AddKey(const std::string& strKey) +{ + // connection is asynchronous -> cannot yet request data from server + //if(!m_tcp.is_connected()) + // return false; + + m_vecKeys.push_back(strKey); +} + +void NicosCache::ClearKeys() +{ + m_vecKeys.clear(); +} + +void NicosCache::RefreshKeys() +{ + std::string strMsg; + for(const std::string& strKey : m_vecKeys) + strMsg += "@"+strKey+"?\n"; + m_tcp.write(strMsg); +} + +void NicosCache::RegisterKeys() +{ + std::string strMsg; + for(const std::string& strKey : m_vecKeys) + strMsg += "@"+strKey+":\n"; + m_tcp.write(strMsg); +} + + +void NicosCache::slot_connected(const std::string& strHost, const std::string& strSrv) +{ + tl::log_info("Connected to ", strHost, " on port ", strSrv, "."); + + QString qstrHost = strHost.c_str(); + QString qstrSrv = strSrv.c_str(); + emit connected(qstrHost, qstrSrv); + + RegisterKeys(); + RefreshKeys(); +} + +void NicosCache::slot_disconnected(const std::string& strHost, const std::string& strSrv) +{ + tl::log_info("Disconnected from ", strHost, " on port ", strSrv, "."); + + emit disconnected(); +} + +void NicosCache::slot_receive(const std::string& str) +{ +#ifndef NDEBUG + tl::log_debug("Received: ", str); +#endif + std::pair pairTimeVal = tl::split_first(str, "@", 1); + std::pair pairKeyVal = tl::split_first(pairTimeVal.second, "=", 1); + if(pairKeyVal.second == "") + { + pairKeyVal = tl::split_first(pairTimeVal.second, "!", 1); + if(pairKeyVal.second != "") + tl::log_warn("Value \"", pairKeyVal.second, "\" for \"", pairKeyVal.first, "\" is marked as invalid."); + else + tl::log_err("Invalid net reply: \"", str, "\""); + } + + + const std::string& strKey = pairKeyVal.first; + const std::string& strVal = pairKeyVal.second; + + + const std::string& strTime = pairTimeVal.first; + t_real dTimestamp = tl::str_to_var(strTime); + + if(strVal.length() == 0) + return; + + CacheVal cacheval; + cacheval.strVal = strVal; + cacheval.dTimestamp = dTimestamp; + m_mapCache[strKey] = cacheval; + + //std::cout << strKey << " = " << strVal << std::endl; + emit updated_cache_value(strKey, cacheval); + + + + CrystalOptions crys; + TriangleOptions triag; + bool bUpdatedVals = 1; + + if(strKey == m_strSampleLattice) + { + std::vector vecLattice = + tl::get_py_array>(strVal); + if(vecLattice.size() != 3) + return; + + crys.bChangedLattice = 1; + for(int i=0; i<3; ++i) + crys.dLattice[i] = vecLattice[i]; + } + else if(strKey == m_strSampleAngles) + { + std::vector vecAngles = + tl::get_py_array>(strVal); + if(vecAngles.size() != 3) + return; + + crys.bChangedLatticeAngles = 1; + for(int i=0; i<3; ++i) + crys.dLatticeAngles[i] = vecAngles[i]; + } + else if(strKey == m_strSampleOrient1) + { + std::vector vecOrient = + tl::get_py_array>(strVal); + if(vecOrient.size() != 3) + return; + + crys.bChangedPlane1 = 1; + for(int i=0; i<3; ++i) + crys.dPlane1[i] = vecOrient[i]; + } + else if(strKey == m_strSampleOrient2) + { + std::vector vecOrient = + tl::get_py_array>(strVal); + if(vecOrient.size() != 3) + return; + + crys.bChangedPlane2 = 1; + + for(int i=0; i<3; ++i) + crys.dPlane2[i] = m_bFlipOrient2 ? -vecOrient[i] : vecOrient[i]; + } + else if(strKey == m_strSampleSpacegroup) + { + crys.strSpacegroup = tl::get_py_string(strVal); + crys.bChangedSpacegroup = 1; + } + else if(strKey == m_strMono2Theta) + { + triag.dMonoTwoTheta = tl::d2r(tl::str_to_var(strVal)); + triag.bChangedMonoTwoTheta = 1; + } + else if(strKey == m_strAna2Theta) + { + triag.dAnaTwoTheta = tl::d2r(tl::str_to_var(strVal)); + triag.bChangedAnaTwoTheta = 1; + } + else if(strKey == m_strSample2Theta) + { + triag.dTwoTheta = tl::d2r(tl::str_to_var(strVal)); + triag.bChangedTwoTheta = 1; + } + else if(strKey == m_strMonoD) + { + triag.dMonoD = tl::str_to_var(strVal); + triag.bChangedMonoD = 1; + } + else if(strKey == m_strAnaD) + { + triag.dAnaD = tl::str_to_var(strVal); + triag.bChangedAnaD = 1; + } + else if(strKey == m_strSampleName) + { + crys.strSampleName = tl::get_py_string(strVal); + } + else if(strKey == m_strSampleTheta || strKey == m_strSamplePsi0) + {} + else + { + bUpdatedVals = 0; + } + + + if(bUpdatedVals && m_mapCache.find(m_strSampleTheta) != m_mapCache.end() + && m_mapCache.find(m_strSamplePsi0) != m_mapCache.end()) + { + // rotation of crystal -> rotation of plane (or triangle) -> sample theta + + t_real dSth = tl::d2r(tl::str_to_var(m_mapCache[m_strSampleTheta].strVal)); + t_real dPsi = tl::d2r(tl::str_to_var(m_mapCache[m_strSamplePsi0].strVal)); + + // sth and psi0 are arbitrary, but together they form the + // angle from ki to the bragg peak at orient1 + triag.dAngleKiVec0 = -dSth-dPsi; + triag.bChangedAngleKiVec0 = 1; + //std::cout << "rotation: " << triag.dAngleKiVec0 << std::endl; + } + + if(bUpdatedVals) + emit vars_changed(crys, triag); +} + +#include "net.moc" +#include "nicos.moc" diff --git a/tools/taz/nicos.h b/tools/taz/nicos.h new file mode 100644 index 0000000..e97d974 --- /dev/null +++ b/tools/taz/nicos.h @@ -0,0 +1,63 @@ +/* + * Connection to Nicos + * @author tweber + * @date 27-aug-2014 + * @license GPLv2 + */ + +#ifndef __NICOS_H__ +#define __NICOS_H__ + +#include "net.h" +#include "tlibs/net/tcp.h" + +#include +#include +#include + +class NicosCache : public NetCache +{ Q_OBJECT + protected: + QSettings* m_pSettings = 0; + + tl::TcpTxtClient<> m_tcp; + std::vector m_vecKeys; + t_mapCacheVal m_mapCache; + + bool m_bFlipOrient2 = 1; + + // endpoints of the TcpClient signals + void slot_connected(const std::string& strHost, const std::string& strSrv); + void slot_disconnected(const std::string& strHost, const std::string& strSrv); + void slot_receive(const std::string& str); + + public: + NicosCache(QSettings* pSettings=0); + virtual ~NicosCache(); + + virtual void connect(const std::string& strHost, const std::string& strPort, + const std::string& strUser, const std::string& strPass) override; + virtual void disconnect() override; + virtual void refresh() override; + + void AddKey(const std::string& strKey); + void ClearKeys(); + + void RefreshKeys(); + void RegisterKeys(); + + protected: + // Nicos device names + std::string m_strSampleName; + std::string m_strSampleLattice, m_strSampleAngles; + std::string m_strSampleOrient1, m_strSampleOrient2; + std::string m_strSampleSpacegroup; + std::string m_strSamplePsi0, m_strSampleTheta, m_strSample2Theta; + std::string m_strMonoTheta, m_strMono2Theta, m_strMonoD; + std::string m_strAnaTheta, m_strAna2Theta, m_strAnaD; + + // rotation sample stick: sth != om, otherwise: sth == om + std::string m_strSampleTheta_aux, m_strSampleTheta_aux_alias; +}; + +#endif diff --git a/tools/taz/proj_lattice.cpp b/tools/taz/proj_lattice.cpp new file mode 100644 index 0000000..acba6c0 --- /dev/null +++ b/tools/taz/proj_lattice.cpp @@ -0,0 +1,405 @@ +/** + * Crystal lattice projections + * @author tweber + * @date may-2016 + * @license GPLv2 + */ + +#include "tlibs/helper/flags.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/log/log.h" +#include "libs/globals.h" +#include "proj_lattice.h" + +#include +#include +#include +#include +#include + + +using t_real = t_real_glob; +using t_vec = ublas::vector; +using t_mat = ublas::matrix; + + +// symbol drawing sizes +#define DEF_PEAK_SIZE 3. +#define MIN_PEAK_SIZE 0.5 +#define MAX_PEAK_SIZE 5.5 + + +#define PROJ_LATTICE_NODE_TYPE_KEY 0 + +enum ProjLatticeNodeType +{ + NODE_PROJ_LATTICE, + NODE_PROJ_LATTICE_OTHER +}; + + + +// -------------------------------------------------------------------------------- + +ProjLatticePoint::ProjLatticePoint() +{ + //setCursor(Qt::ArrowCursor); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemIgnoresTransformations); +} + +QRectF ProjLatticePoint::boundingRect() const +{ + return QRectF(-5., -5., 10., 10.); +} + +void ProjLatticePoint::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + painter->setBrush(m_color); + painter->drawEllipse(QRectF(-m_dRadius, -m_dRadius, m_dRadius*2., m_dRadius*2.)); + + if(m_strLabel != "") + { + painter->setPen(m_color); + QRectF rect = boundingRect(); + rect.setTop(rect.top()+16.5); + //painter->drawRect(rect); + painter->drawText(rect, Qt::AlignHCenter|Qt::AlignTop, m_strLabel); + } +} + +// -------------------------------------------------------------------------------- + + +ProjLattice::ProjLattice(ProjLatticeScene& scene) + : m_scene(scene) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setAcceptedMouseButtons(0); + m_bReady = 1; +} + +ProjLattice::~ProjLattice() +{ + m_bReady = 0; + ClearPeaks(); +} + +QRectF ProjLattice::boundingRect() const +{ + return QRectF(-1000.*m_dZoom, -1000.*m_dZoom, 2000.*m_dZoom, 2000.*m_dZoom); +} + +void ProjLattice::SetZoom(t_real dZoom) +{ + m_dZoom = dZoom; + m_scene.update(); +} + +void ProjLattice::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); +} + +template +static void to_proj(T x, T y, T z, T& xg, T& yg, bool bGnom=1) +{ + T rho, phi, theta, phi_crys, theta_crys; + std::tie(rho, phi, theta) = tl::cart_to_sph(x, y, z); + std::tie(phi_crys, theta_crys) = tl::sph_to_crys(phi, theta); + + if(bGnom) + std::tie(xg, yg) = tl::gnomonic_proj(phi_crys, theta_crys); + else + std::tie(xg, yg) = tl::stereographic_proj(phi_crys, theta_crys, T(1)); +} + +void ProjLattice::CalcPeaks(const LatticeCommon& latticecommon, bool bIsRecip) +{ + ClearPeaks(); + + const tl::Lattice* pLatticeOther = nullptr; + if(bIsRecip) + { + m_lattice = latticecommon.recip; + pLatticeOther = &latticecommon.lattice; + m_matPlane_inv = latticecommon.matPlane_inv; + } + else + { + m_lattice = latticecommon.lattice; + pLatticeOther = &latticecommon.recip; + // m_matPlane_inv = ! TODO ! + } + + + t_mat matPersp; + t_real dLattConst = std::min(pLatticeOther->GetA(), pLatticeOther->GetB()); + dLattConst = std::min(dLattConst, pLatticeOther->GetC()); + dLattConst = 2.*tl::get_pi() / dLattConst; + + if(m_proj == LatticeProj::PERSPECTIVE) + matPersp = tl::perspective_matrix(tl::d2r(5.), 1., 0.01, 100.); + + const std::string strAA = tl::get_spec_char_utf8("AA"); + bool bModifiedRadii = 0; + + for(int ih=-m_iMaxPeaks; ih<=m_iMaxPeaks; ++ih) + for(int ik=-m_iMaxPeaks; ik<=m_iMaxPeaks; ++ik) + for(int il=-m_iMaxPeaks; il<=m_iMaxPeaks; ++il) + { + if(bIsRecip && latticecommon.pSpaceGroup && + !latticecommon.pSpaceGroup->HasReflection(ih, ik, il)) + continue; + + const t_real h = t_real(ih), k = t_real(ik), l = t_real(il); + t_vec vecPeak = m_lattice.GetPos(h,k,l); + + t_vec vecCoord = ublas::prod(m_matPlane_inv, vecPeak); + t_real dX = vecCoord[0], dY = vecCoord[1]; + switch(m_proj) + { + case LatticeProj::PARALLEL: + break; + case LatticeProj::PERSPECTIVE: + vecCoord.resize(4,1); + vecCoord[2] += dLattConst*m_iMaxPeaks*4.75; + vecCoord[3] = 1.; + vecCoord = ublas::prod(matPersp, vecCoord); + vecCoord /= vecCoord[3]; + dX = -vecCoord[0]; + dY = -vecCoord[1]; + break; + case LatticeProj::GNOMONIC: + to_proj(vecCoord[0], vecCoord[2], vecCoord[1], dX, dY, true); + break; + case LatticeProj::STEREOGRAPHIC: + to_proj(vecCoord[0], vecCoord[2], vecCoord[1], dX, dY, false); + break; + } + + dX *=m_dScaleFactor; dY = -dY*m_dScaleFactor; + if(tl::is_nan_or_inf(dX) || tl::is_nan_or_inf(dY)) + continue; + + auto iterPeak = std::find_if(m_vecPeaks.begin(), m_vecPeaks.end(), + [dX, dY](const ProjLatticePoint* pPeak) -> bool + { + return tl::float_equal(pPeak->x(), dX, g_dEpsGfx) && + tl::float_equal(pPeak->y(), dY, g_dEpsGfx); + }); + + ProjLatticePoint *pPeak = nullptr; + if(iterPeak == m_vecPeaks.end()) + { + pPeak = new ProjLatticePoint(); + if(ih==0 && ik==0 && il==0) + pPeak->SetColor(Qt::green); + pPeak->setPos(dX, dY); + pPeak->setData(PROJ_LATTICE_NODE_TYPE_KEY, NODE_PROJ_LATTICE); + + m_vecPeaks.push_back(pPeak); + m_scene.addItem(pPeak); + } + else + { + pPeak = *iterPeak; + } + + if(bIsRecip && latticecommon.CanCalcStructFact()) + { + t_real dF = 0.; + std::tie(std::ignore, dF, std::ignore) = + latticecommon.GetStructFact(vecPeak); + + pPeak->AddRadius(dF); + bModifiedRadii = 1; + } + else + { + pPeak->SetRadius(DEF_PEAK_SIZE); + } + + std::ostringstream ostrTip; + ostrTip.precision(g_iPrecGfx); + + ostrTip << "(" << ih << " " << ik << " " << il << ")"; + pPeak->AddTooltip(QString::fromUtf8(ostrTip.str().c_str(), ostrTip.str().length())); + } + + + t_real dMinRad = std::numeric_limits::max(), dMaxRad = -1.; + + if(bModifiedRadii) + { + for(ProjLatticePoint* pPeak : m_vecPeaks) + { + dMinRad = std::min(dMinRad, pPeak->GetRadius()); + dMaxRad = std::max(dMaxRad, pPeak->GetRadius()); + } + } + + for(ProjLatticePoint* pPeak : m_vecPeaks) + { + if(bModifiedRadii) + { + if(!tl::float_equal(dMinRad, dMaxRad, g_dEpsGfx)) + { + t_real dRadScale = (pPeak->GetRadius()-dMinRad) / (dMaxRad-dMinRad); + pPeak->SetRadius(tl::lerp(MIN_PEAK_SIZE, MAX_PEAK_SIZE, dRadScale)); + } + else + { + pPeak->SetRadius(DEF_PEAK_SIZE); + } + } + + pPeak->SetTooltip(); + } + + this->update(); +} + +void ProjLattice::ClearPeaks() +{ + for(ProjLatticePoint*& pPeak : m_vecPeaks) + { + if(pPeak) + { + m_scene.removeItem(pPeak); + delete pPeak; + pPeak = nullptr; + } + } + m_vecPeaks.clear(); +} + +// -------------------------------------------------------------------------------- + + +ProjLatticeScene::ProjLatticeScene(QObject *pParent) + : QGraphicsScene(pParent), m_pLatt(new ProjLattice(*this)) +{ + this->addItem(m_pLatt); +} + +ProjLatticeScene::~ProjLatticeScene() +{ + delete m_pLatt; +} + +void ProjLatticeScene::scaleChanged(t_real dTotalScale) +{ + if(!m_pLatt) return; + m_pLatt->SetZoom(dTotalScale); +} + +void ProjLatticeScene::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 1; + QGraphicsScene::mousePressEvent(pEvt); +} + + +void ProjLatticeScene::drawBackground(QPainter* pPainter, const QRectF& rect) +{ + QGraphicsScene::drawBackground(pPainter, rect); +} + +void ProjLatticeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) +{ + bool bHandled = 0; + bool bAllowed = 1; + +/* + // TODO: inverse trafo + if(m_pLatt) + { + const t_real dX = pEvt->scenePos().x()/m_pLatt->GetScaleFactor(); + const t_real dY = -pEvt->scenePos().y()/m_pLatt->GetScaleFactor(); + + t_vec vecHKL = ...; + tl::set_eps_0(vecHKL, g_dEps); + + if(vecHKL.size()==3) + { + emit coordsChanged(vecHKL[0], vecHKL[1], vecHKL[2], 0, 0., 0., 0.); + } + } +*/ + + // node dragging + if(m_bMousePressed) + { + QGraphicsItem* pCurItem = mouseGrabberItem(); + if(pCurItem) + { + const int iNodeType = pCurItem->data(PROJ_LATTICE_NODE_TYPE_KEY).toInt(); + + // nothing there yet... + } + } + + if(!bHandled && bAllowed) + QGraphicsScene::mouseMoveEvent(pEvt); +} + +void ProjLatticeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 0; + + QGraphicsScene::mouseReleaseEvent(pEvt); +} + +void ProjLatticeScene::keyPressEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 1; + + QGraphicsScene::keyPressEvent(pEvt); +} + +void ProjLatticeScene::keyReleaseEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 0; + + QGraphicsScene::keyReleaseEvent(pEvt); +} + + +// -------------------------------------------------------------------------------- + + +ProjLatticeView::ProjLatticeView(QWidget* pParent) + : QGraphicsView(pParent) +{ + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + setDragMode(QGraphicsView::ScrollHandDrag); + setMouseTracking(1); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); +} + +ProjLatticeView::~ProjLatticeView() +{} + +void ProjLatticeView::wheelEvent(QWheelEvent *pEvt) +{ +#if QT_VER>=5 + const t_real dDelta = pEvt->angleDelta().y()/8. / 150.; +#else + const t_real dDelta = pEvt->delta()/8. / 150.; +#endif + + t_real dScale = std::pow(2., dDelta); + this->scale(dScale, dScale); + m_dTotalScale *= dScale; + emit scaleChanged(m_dTotalScale); +} + + +#include "proj_lattice.moc" diff --git a/tools/taz/proj_lattice.h b/tools/taz/proj_lattice.h new file mode 100644 index 0000000..7a92713 --- /dev/null +++ b/tools/taz/proj_lattice.h @@ -0,0 +1,173 @@ +/** + * Crystal lattice projections + * @author tweber + * @date may-2016 + * @license GPLv2 + */ + +#ifndef __TAZ_PROJ_LATTICE_H__ +#define __TAZ_PROJ_LATTICE_H__ + +#include "tlibs/math/linalg.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/geo.h" + +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/spacegroups/latticehelper.h" + +#include "tasoptions.h" + +#include +#include +#include +#include +#include +#include +#if QT_VER>=5 + #include +#endif + +namespace ublas = boost::numeric::ublas; + +enum class LatticeProj +{ + GNOMONIC, + STEREOGRAPHIC, + PARALLEL, + PERSPECTIVE +}; + +class ProjLattice; + +class ProjLatticePoint : public QGraphicsItem +{ + protected: + QColor m_color = Qt::red; + QString m_strLabel; + QString m_strTT; + t_real_glob m_dRadius = 0.; + + protected: + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + public: + ProjLatticePoint(); + + void SetLabel(const QString& str) { m_strLabel = str; } + void SetColor(const QColor& col) { m_color = col; } + + void AddTooltip(const QString& strTT) { if(m_strTT.length()) m_strTT+=", "; m_strTT += strTT; } + void SetTooltip() { setToolTip(m_strTT);} + + void SetRadius(t_real_glob dRad) { m_dRadius = dRad; } + void AddRadius(t_real_glob dRad) { m_dRadius += dRad; } + t_real_glob GetRadius() const { return m_dRadius; } +}; + + +class ProjLatticeScene; +class ProjLattice : public QGraphicsItem +{ + protected: + bool m_bReady = 0; + ProjLatticeScene &m_scene; + + t_real_glob m_dScaleFactor = 150.; // pixels per A for zoom == 1. + t_real_glob m_dZoom = 1.; + int m_iMaxPeaks = 5; + + tl::Lattice m_lattice; + ublas::matrix m_matPlane, m_matPlane_inv; + std::vector m_vecPeaks; + + LatticeProj m_proj = LatticeProj::STEREOGRAPHIC; + + protected: + virtual QRectF boundingRect() const override; + + public: + ProjLattice(ProjLatticeScene& scene); + virtual ~ProjLattice(); + + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + void SetReady(bool bReady) { m_bReady = bReady; } + bool IsReady() const { return m_bReady; } + + const ublas::matrix& GetPlane() const { return m_matPlane; } + + void SetProjection(LatticeProj proj) { m_proj = proj; } + + public: + bool HasPeaks() const { return m_vecPeaks.size()!=0 && m_lattice.IsInited(); } + void ClearPeaks(); + void CalcPeaks(const LatticeCommon& recipcommon, bool bIsRecip=1); + + void SetMaxPeaks(int iMax) { m_iMaxPeaks = iMax; } + unsigned int GetMaxPeaks() const { return m_iMaxPeaks; } + void SetZoom(t_real_glob dZoom); + t_real_glob GetZoom() const { return m_dZoom; } + + public: + t_real_glob GetScaleFactor() const { return m_dScaleFactor; } + void SetScaleFactor(t_real_glob dScale) { m_dScaleFactor = dScale; } + + const tl::Lattice& GetProjLattice() const { return m_lattice; } +}; + + +class ProjLatticeScene : public QGraphicsScene +{ Q_OBJECT + protected: + ProjLattice *m_pLatt; + + bool m_bSnap = 0; + bool m_bMousePressed = 0; + + public: + ProjLatticeScene(QObject *pParent=nullptr); + virtual ~ProjLatticeScene(); + + const ProjLattice* GetLattice() const { return m_pLatt; } + ProjLattice* GetLattice() { return m_pLatt; } + + public slots: + void scaleChanged(t_real_glob dTotalScale); + + signals: + void coordsChanged(t_real_glob dh, t_real_glob dk, t_real_glob dl, + bool bHasNearest, + t_real_glob dNearestH, t_real_glob dNearestK, t_real_glob dNearestL); + + protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + + virtual void keyPressEvent(QKeyEvent *pEvt) override; + virtual void keyReleaseEvent(QKeyEvent *pEvt) override; + + virtual void drawBackground(QPainter*, const QRectF&) override; +}; + + +class ProjLatticeView : public QGraphicsView +{ + Q_OBJECT + protected: + t_real_glob m_dTotalScale = 1.; + virtual void wheelEvent(QWheelEvent* pEvt) override; + + public: + ProjLatticeView(QWidget* pParent = 0); + virtual ~ProjLatticeView(); + + signals: + void scaleChanged(t_real_glob dTotalScale); +}; + +#endif diff --git a/tools/taz/real_lattice.cpp b/tools/taz/real_lattice.cpp new file mode 100644 index 0000000..c5b87f1 --- /dev/null +++ b/tools/taz/real_lattice.cpp @@ -0,0 +1,576 @@ +/** + * Real crystal lattice + * @author tweber + * @date 2014 - 2016 + * @license GPLv2 + */ + +#include "tlibs/helper/flags.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/atoms.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/log/log.h" +#include "libs/globals.h" +#include "real_lattice.h" + +#include +#include +#include +#include +#include + + +using t_real = t_real_glob; +using t_vec = ublas::vector; +using t_mat = ublas::matrix; + + +#define REAL_LATTICE_NODE_TYPE_KEY 0 + +enum LatticeNodeType +{ + NODE_REAL_LATTICE, + NODE_REAL_LATTICE_ATOM, + + NODE_REAL_LATTICE_OTHER +}; + + + +// -------------------------------------------------------------------------------- + +LatticePoint::LatticePoint() +{ + //setCursor(Qt::ArrowCursor); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemIgnoresTransformations); +} + +QRectF LatticePoint::boundingRect() const +{ + return QRectF(-35., -10., 70., 50.); +} + +void LatticePoint::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + painter->setBrush(m_color); + painter->drawEllipse(QRectF(-3., -3., 6., 6.)); + + if(m_strLabel != "") + { + painter->setPen(m_color); + QRectF rect = boundingRect(); + rect.setTop(rect.top()+16.5); + //painter->drawRect(rect); + painter->drawText(rect, Qt::AlignHCenter|Qt::AlignTop, m_strLabel); + } +} + +// -------------------------------------------------------------------------------- + +LatticeAtom::LatticeAtom() +{ + //setCursor(Qt::ArrowCursor); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemIgnoresTransformations); +} + +QRectF LatticeAtom::boundingRect() const +{ + return QRectF(-35., -10., 70., 50.); +} + +void LatticeAtom::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + painter->setBrush(m_color); + painter->setPen(Qt::darkCyan); + painter->drawEllipse(QRectF(-3., -3., 6., 6.)); + + if(m_strElem != "") + { + painter->setPen(m_color); + QRectF rect = boundingRect(); + rect.setTop(rect.top()+16.5); + //painter->drawRect(rect); + painter->drawText(rect, Qt::AlignHCenter|Qt::AlignTop, m_strElem.c_str()); + } +} + + +// -------------------------------------------------------------------------------- + + +RealLattice::RealLattice(LatticeScene& scene) + : m_scene(scene) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setAcceptedMouseButtons(0); + m_bReady = 1; +} + +RealLattice::~RealLattice() +{ + m_bReady = 0; + ClearPeaks(); +} + +QRectF RealLattice::boundingRect() const +{ + return QRectF(-1000.*m_dZoom, -1000.*m_dZoom, 2000.*m_dZoom, 2000.*m_dZoom); +} + +void RealLattice::SetZoom(t_real dZoom) +{ + m_dZoom = dZoom; + m_scene.update(); +} + +void RealLattice::SetWSVisible(bool bVisible) +{ + m_bShowWS = bVisible; + this->update(); +} + +void RealLattice::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + + // Wigner-Seitz cell + if(m_bShowWS && m_ws.IsValid()) + { + QPen penOrg = painter->pen(); + painter->setPen(Qt::lightGray); + + const t_vec& vecCentral = m_ws.GetCentralReflex() * m_dScaleFactor*m_dZoom; + //std::cout << vecCentral << std::endl; + for(const LatticePoint* pPeak : m_vecPeaks) + { + QPointF peakPos = pPeak->pos(); + peakPos *= m_dZoom; + + const tl::Brillouin2D::t_vertices& verts = m_ws.GetVertices(); + for(const tl::Brillouin2D::t_vecpair& vertpair : verts) + { + const t_vec& vec1 = vertpair.first * m_dScaleFactor * m_dZoom; + const t_vec& vec2 = vertpair.second * m_dScaleFactor * m_dZoom; + + QPointF pt1 = vec_to_qpoint(vec1 - vecCentral) + peakPos; + QPointF pt2 = vec_to_qpoint(vec2 - vecCentral) + peakPos; + + QLineF lineBZ(pt1, pt2); + painter->drawLine(lineBZ); + } + } + + painter->setPen(penOrg); + } +} + +void RealLattice::CalcPeaks(const LatticeCommon& latticecommon) +{ + ClearPeaks(); + m_kdLattice.Unload(); + m_lattice = latticecommon.lattice; + m_matPlane = latticecommon.matPlaneReal; + m_matPlane_inv = latticecommon.matPlaneReal_inv; + + // central peak for WS cell calculation + ublas::vector veciCent = tl::make_vec({0.,0.,0.}); + + const std::string strAA = tl::get_spec_char_utf8("AA"); + + // -------------------------------------------------------------------- + // atom positions in unit cell + std::vector colors = {QColor(127,0,0), QColor(0,127,0), QColor(0,0,127), + QColor(127,127,0), QColor(0,127,127), QColor(127,0,127)}; + + for(std::size_t iAtom=0; iAtomm_strElem = strElem; + pAtom->m_vecPos = std::move(vecThisAtom); + pAtom->m_vecProj = latticecommon.planeReal.GetDroppedPerp(pAtom->m_vecPos/*, &pAtom->m_dProjDist*/); + pAtom->m_dProjDist = latticecommon.planeReal.GetDist(pAtom->m_vecPos); + + t_vec vecCoord = ublas::prod(m_matPlane_inv, pAtom->m_vecProj); + t_real dX = vecCoord[0], dY = -vecCoord[1]; + + pAtom->setPos(dX * m_dScaleFactor, dY * m_dScaleFactor); + pAtom->setData(REAL_LATTICE_NODE_TYPE_KEY, NODE_REAL_LATTICE_ATOM); + + std::ostringstream ostrTip; + ostrTip.precision(g_iPrecGfx); + ostrTip << pAtom->m_strElem; + ostrTip << "\n(" + << vecThisAtomFrac[0] << ", " + << vecThisAtomFrac[1] << ", " + << vecThisAtomFrac[2] << ") frac"; + ostrTip << "\n(" + << vecThisAtom[0] << ", " + << vecThisAtom[1] << ", " + << vecThisAtom[2] << ") " << strAA; + ostrTip << "\nDistance to Plane: " << pAtom->m_dProjDist << " " << strAA; + pAtom->setToolTip(QString::fromUtf8(ostrTip.str().c_str(), ostrTip.str().length())); + pAtom->SetColor(colors[iCurAtomType % colors.size()]); + + m_scene.addItem(pAtom); + } + // -------------------------------------------------------------------- + + + + std::list> lstPeaksForKd; + + for(int ih=-m_iMaxPeaks; ih<=m_iMaxPeaks; ++ih) + for(int ik=-m_iMaxPeaks; ik<=m_iMaxPeaks; ++ik) + for(int il=-m_iMaxPeaks; il<=m_iMaxPeaks; ++il) + { + const t_real h = t_real(ih), k = t_real(ik), l = t_real(il); + t_vec vecPeak = m_lattice.GetPos(h,k,l); + + // add peak in A and in fractional units + lstPeaksForKd.push_back(std::vector{vecPeak[0],vecPeak[1],vecPeak[2], h,k,l}); + + t_real dDist = 0.; + t_vec vecDropped = latticecommon.planeReal.GetDroppedPerp(vecPeak, &dDist); + + if(tl::float_equal(dDist, 0., m_dPlaneDistTolerance)) + { + t_vec vecCoord = ublas::prod(m_matPlane_inv, vecDropped); + t_real dX = vecCoord[0], dY = -vecCoord[1]; + + LatticePoint *pPeak = new LatticePoint(); + if(ih==0 && ik==0 && il==0) + pPeak->SetColor(Qt::green); + pPeak->setPos(dX * m_dScaleFactor, dY * m_dScaleFactor); + pPeak->setData(REAL_LATTICE_NODE_TYPE_KEY, NODE_REAL_LATTICE); + + std::ostringstream ostrTip; + ostrTip.precision(g_iPrecGfx); + + ostrTip << "(" << ih << " " << ik << " " << il << ")"; + pPeak->SetLabel(ostrTip.str().c_str()); + + tl::set_eps_0(vecPeak); + ostrTip << " frac\n"; + ostrTip << "(" + << vecPeak[0] << ", " + << vecPeak[1] << ", " + << vecPeak[2] << ") " << strAA; + //ostrTip << "\ndistance to plane: " << dDist << " " << strAA; + pPeak->setToolTip(QString::fromUtf8(ostrTip.str().c_str(), ostrTip.str().length())); + + m_vecPeaks.push_back(pPeak); + m_scene.addItem(pPeak); + + + // Wigner-Seitz cell + if(ih==veciCent[0] && ik==veciCent[1] && il==veciCent[2]) + { + t_vec vecCentral = tl::make_vec({dX, dY}); + //log_debug("Central ", ih, ik, il, ": ", vecCentral); + m_ws.SetCentralReflex(vecCentral); + } + // TODO: check if 2 next neighbours is sufficient for all space groups + else if(std::abs(ih-veciCent[0])<=2 + && std::abs(ik-veciCent[1])<=2 + && std::abs(il-veciCent[2])<=2) + { + t_vec vecN = tl::make_vec({dX, dY}); + //log_debug("Reflex: ", vecN); + m_ws.AddReflex(vecN); + } + } + } + + m_ws.CalcBZ(); + //for(LatticePoint* pPeak : m_vecPeaks) + // pPeak->SetBZ(&m_ws); + + m_kdLattice.Load(lstPeaksForKd, 3); + + this->update(); +} + +t_vec RealLattice::GetHKLFromPlanePos(t_real x, t_real y) const +{ + if(!HasPeaks()) + return t_vec(); + + t_vec vec = x*tl::get_column(m_matPlane, 0) + + y*tl::get_column(m_matPlane, 1); + return m_lattice.GetHKL(vec); +} + +void RealLattice::ClearPeaks() +{ + m_ws.Clear(); + + for(LatticePoint*& pPeak : m_vecPeaks) + { + if(pPeak) + { + m_scene.removeItem(pPeak); + delete pPeak; + pPeak = nullptr; + } + } + m_vecPeaks.clear(); + + for(LatticeAtom*& pAtom : m_vecAtoms) + { + if(pAtom) + { + m_scene.removeItem(pAtom); + delete pAtom; + pAtom = nullptr; + } + } + m_vecAtoms.clear(); +} + +// -------------------------------------------------------------------------------- + + +LatticeScene::LatticeScene(QObject *pParent) + : QGraphicsScene(pParent), m_pLatt(new RealLattice(*this)) +{ + this->addItem(m_pLatt); +} + +LatticeScene::~LatticeScene() +{ + delete m_pLatt; +} + +void LatticeScene::scaleChanged(t_real dTotalScale) +{ + if(!m_pLatt) return; + m_pLatt->SetZoom(dTotalScale); +} + +void LatticeScene::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 1; + QGraphicsScene::mousePressEvent(pEvt); +} + + +#ifdef USE_GIL + +#include "tlibs/gfx/gil.h" +namespace gil = boost::gil; + +bool LatticeScene::ExportWSAccurate(const char* pcFile) const +{ + if(!m_pLatt) return false; + + const int iW = 720; + const int iH = 720; + + gil::rgb8_view_t view; + std::vector vecPix; + tl::create_imgview(iW, iH, vecPix, view); + + const int iMaxPeaks = m_pLatt->GetMaxPeaks(); + int iXMid = sceneRect().left() + (sceneRect().right()-sceneRect().left())/2; + int iYMid = sceneRect().top() + (sceneRect().bottom()-sceneRect().top())/2; + + int _iY=0; + for(int iY=iYMid-iH/2; iYGetHKLFromPlanePos(dX, -dY); + if(vecHKL.size()!=3) return false; + vecHKL /= m_pLatt->GetScaleFactor(); + + const std::vector* pvecNearest = nullptr; + const tl::Kd& kd = m_pLatt->GetKdLattice(); + t_vec vecHKLA = m_pLatt->GetRealLattice().GetPos(vecHKL[0], vecHKL[1], vecHKL[2]); + + if(kd.GetRootNode()) + { + std::vector stdvecHKL{vecHKLA[0], vecHKLA[1], vecHKLA[2]}; + pvecNearest = &kd.GetNearestNode(stdvecHKL); + } + + if(!pvecNearest) return false; + t_real dDist = ublas::norm_2(tl::make_vec({(*pvecNearest)[0], (*pvecNearest)[1], (*pvecNearest)[2]}) - vecHKLA); + + bool bIsDirectBeam = 0; + if(tl::float_equal((*pvecNearest)[3], 0.) && tl::float_equal((*pvecNearest)[4], 0.) && tl::float_equal((*pvecNearest)[5], 0.)) + bIsDirectBeam = 1; + + int iR = ((*pvecNearest)[3]+iMaxPeaks) * 255 / (iMaxPeaks*2); + int iG = ((*pvecNearest)[4]+iMaxPeaks) * 255 / (iMaxPeaks*2); + int iB = ((*pvecNearest)[5]+iMaxPeaks) * 255 / (iMaxPeaks*2); + t_real dBraggAmp = tl::gauss_model(dDist, 0., 0.01, 255., 0.); + iR += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + iG += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + iB += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + + iR = tl::clamp(iR, 0, 255); + iG = tl::clamp(iG, 0, 255); + iB = tl::clamp(iB, 0, 255); + + iterRow[_iX] = gil::rgb8_pixel_t((unsigned char)iR, (unsigned char)iG, (unsigned char)iB); + } + + //tl::log_info("BZ export: Line ", _iY+1, " of ", iH); + } + + if(!tl::save_view(pcFile, &view)) + { + tl::log_err("Cannot write image \"", pcFile, "\"."); + return false; + } + + return true; +} + +#else +bool LatticeScene::ExportWSAccurate(const char* pcFile) const { return 0; } +#endif + + +void LatticeScene::drawBackground(QPainter* pPainter, const QRectF& rect) +{ + QGraphicsScene::drawBackground(pPainter, rect); + // TODO: draw accurate WS cell +} + +void LatticeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) +{ + bool bHandled = 0; + bool bAllowed = 1; + + + // tooltip + if(m_pLatt) + { + const t_real dX = pEvt->scenePos().x()/m_pLatt->GetScaleFactor(); + const t_real dY = -pEvt->scenePos().y()/m_pLatt->GetScaleFactor(); + + t_vec vecHKL = m_pLatt->GetHKLFromPlanePos(dX, dY); + tl::set_eps_0(vecHKL, g_dEps); + + if(vecHKL.size()==3) + { + //std::ostringstream ostrPos; + //ostrPos << "(" << vecHKL[0] << ", " << vecHKL[1] << ", " << vecHKL[2] << ")"; + //QToolTip::showText(pEvt->screenPos(), ostrPos.str().c_str()); + + const std::vector* pvecNearest = nullptr; + + const tl::Kd& kd = m_pLatt->GetKdLattice(); + const tl::Lattice& lattice = m_pLatt->GetRealLattice(); + t_vec vecHKLA = lattice.GetPos(vecHKL[0], vecHKL[1], vecHKL[2]); + + if(kd.GetRootNode()) + { + std::vector stdvecHKL{vecHKLA[0], vecHKLA[1], vecHKLA[2]}; + pvecNearest = &kd.GetNearestNode(stdvecHKL); + if(pvecNearest->size() < 6) + { + pvecNearest = nullptr; + tl::log_warn("Invalid WS node."); + } + } + + emit coordsChanged(vecHKL[0], vecHKL[1], vecHKL[2], + pvecNearest != nullptr, + pvecNearest?(*pvecNearest)[3]:0., + pvecNearest?(*pvecNearest)[4]:0., + pvecNearest?(*pvecNearest)[5]:0.); + } + } + + + // node dragging + if(m_bMousePressed) + { + QGraphicsItem* pCurItem = mouseGrabberItem(); + if(pCurItem) + { + const int iNodeType = pCurItem->data(REAL_LATTICE_NODE_TYPE_KEY).toInt(); + + // nothing there yet... + } + } + + if(!bHandled && bAllowed) + QGraphicsScene::mouseMoveEvent(pEvt); +} + +void LatticeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 0; + + QGraphicsScene::mouseReleaseEvent(pEvt); +} + +void LatticeScene::keyPressEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 1; + + QGraphicsScene::keyPressEvent(pEvt); +} + +void LatticeScene::keyReleaseEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 0; + + QGraphicsScene::keyReleaseEvent(pEvt); +} + + +// -------------------------------------------------------------------------------- + + +LatticeView::LatticeView(QWidget* pParent) + : QGraphicsView(pParent) +{ + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + setDragMode(QGraphicsView::ScrollHandDrag); + setMouseTracking(1); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); +} + +LatticeView::~LatticeView() +{} + +void LatticeView::wheelEvent(QWheelEvent *pEvt) +{ +#if QT_VER>=5 + const t_real dDelta = pEvt->angleDelta().y()/8. / 150.; +#else + const t_real dDelta = pEvt->delta()/8. / 150.; +#endif + + t_real dScale = std::pow(2., dDelta); + this->scale(dScale, dScale); + m_dTotalScale *= dScale; + emit scaleChanged(m_dTotalScale); +} + + +#include "real_lattice.moc" diff --git a/tools/taz/real_lattice.h b/tools/taz/real_lattice.h new file mode 100644 index 0000000..6f14c43 --- /dev/null +++ b/tools/taz/real_lattice.h @@ -0,0 +1,190 @@ +/** + * Real crystal lattice + * @author tweber + * @date 2014 - 2016 + * @license GPLv2 + */ + +#ifndef __TAZ_REAL_LATTICE_H__ +#define __TAZ_REAL_LATTICE_H__ + +#include "tlibs/math/linalg.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/bz.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/kd.h" + +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/spacegroups/latticehelper.h" + +#include "tasoptions.h" +#include "dialogs/AtomsDlg.h" + +#include +#include +#include +#include +#include +#include +#if QT_VER>=5 + #include +#endif + +namespace ublas = boost::numeric::ublas; + + +class RealLattice; + +class LatticePoint : public QGraphicsItem +{ + protected: + QColor m_color = Qt::red; + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + protected: + QString m_strLabel; + + public: + LatticePoint(); + + void SetLabel(const QString& str) { m_strLabel = str; } + void SetColor(const QColor& col) { m_color = col; } +}; + + +class LatticeAtom : public QGraphicsItem +{ + friend class RealLattice; + + protected: + QColor m_color = Qt::cyan; + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + protected: + std::string m_strElem; + ublas::vector m_vecPos; + ublas::vector m_vecProj; + t_real_glob m_dProjDist = 0.; + + public: + LatticeAtom(); + void SetColor(const QColor& col) { m_color = col; } +}; + + +class LatticeScene; +class RealLattice : public QGraphicsItem +{ + protected: + bool m_bReady = 0; + LatticeScene &m_scene; + + t_real_glob m_dScaleFactor = 48.; // pixels per A for zoom == 1. + t_real_glob m_dZoom = 1.; + t_real_glob m_dPlaneDistTolerance = 0.01; + int m_iMaxPeaks = 7; + + tl::Lattice m_lattice; + ublas::matrix m_matPlane, m_matPlane_inv; + std::vector m_vecPeaks; + std::vector m_vecAtoms; + + tl::Kd m_kdLattice; + + bool m_bShowWS = 1; + tl::Brillouin2D m_ws; // Wigner-Seitz cell + + protected: + virtual QRectF boundingRect() const override; + + public: + RealLattice(LatticeScene& scene); + virtual ~RealLattice(); + + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + void SetReady(bool bReady) { m_bReady = bReady; } + bool IsReady() const { return m_bReady; } + + const ublas::matrix& GetPlane() const { return m_matPlane; } + + public: + bool HasPeaks() const { return m_vecPeaks.size()!=0 && m_lattice.IsInited(); } + void ClearPeaks(); + void CalcPeaks(const LatticeCommon& latticecommon); + + void SetPlaneDistTolerance(t_real_glob dTol) { m_dPlaneDistTolerance = dTol; } + void SetMaxPeaks(int iMax) { m_iMaxPeaks = iMax; } + unsigned int GetMaxPeaks() const { return m_iMaxPeaks; } + void SetZoom(t_real_glob dZoom); + t_real_glob GetZoom() const { return m_dZoom; } + + void SetWSVisible(bool bVisible); + + const tl::Kd& GetKdLattice() const { return m_kdLattice; } + + public: + t_real_glob GetScaleFactor() const { return m_dScaleFactor; } + void SetScaleFactor(t_real_glob dScale) { m_dScaleFactor = dScale; } + + ublas::vector GetHKLFromPlanePos(t_real_glob x, t_real_glob y) const; + const tl::Lattice& GetRealLattice() const { return m_lattice; } +}; + + +class LatticeScene : public QGraphicsScene +{ Q_OBJECT + protected: + RealLattice *m_pLatt; + bool m_bSnap = 0; + bool m_bMousePressed = 0; + + public: + LatticeScene(QObject *pParent=nullptr); + virtual ~LatticeScene(); + + const RealLattice* GetLattice() const { return m_pLatt; } + RealLattice* GetLattice() { return m_pLatt; } + + bool ExportWSAccurate(const char* pcFile) const; + + public slots: + void scaleChanged(t_real_glob dTotalScale); + + signals: + void coordsChanged(t_real_glob dh, t_real_glob dk, t_real_glob dl, + bool bHasNearest, + t_real_glob dNearestH, t_real_glob dNearestK, t_real_glob dNearestL); + + protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + + virtual void keyPressEvent(QKeyEvent *pEvt) override; + virtual void keyReleaseEvent(QKeyEvent *pEvt) override; + + virtual void drawBackground(QPainter*, const QRectF&) override; +}; + + +class LatticeView : public QGraphicsView +{ + Q_OBJECT + protected: + t_real_glob m_dTotalScale = 1.; + virtual void wheelEvent(QWheelEvent* pEvt) override; + + public: + LatticeView(QWidget* pParent = 0); + virtual ~LatticeView(); + + signals: + void scaleChanged(t_real_glob dTotalScale); +}; + +#endif diff --git a/tools/taz/recip3d.cpp b/tools/taz/recip3d.cpp new file mode 100644 index 0000000..bbeb745 --- /dev/null +++ b/tools/taz/recip3d.cpp @@ -0,0 +1,131 @@ +/* + * Scattering Triangle Tool + * @author tweber + * @date mar-2014 + * @license GPLv2 + */ + +#include "recip3d.h" +#include "tlibs/math/geo.h" +#include + + +using t_real = t_real_glob; + +Recip3DDlg::Recip3DDlg(QWidget* pParent, QSettings *pSettings) + : QDialog(pParent), m_pPlot(new PlotGl(this, pSettings)) +{ + setWindowFlags(Qt::Tool); + setWindowTitle("Reciprocal Space"); + + QGridLayout *gridLayout = new QGridLayout(this); + m_pPlot->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + gridLayout->addWidget(m_pPlot, 0, 0, 1, 1); + + resize(640, 480); +} + +Recip3DDlg::~Recip3DDlg() +{ + if(m_pPlot) + { + delete m_pPlot; + m_pPlot = 0; + } +} + + +void Recip3DDlg::CalcPeaks(const LatticeCommon& recipcommon) +{ + const tl::Lattice& recip = recipcommon.recip; + const SpaceGroup* pSpaceGroup = recipcommon.pSpaceGroup; + const tl::Plane& plane = recipcommon.plane; + + + const unsigned int iObjCnt = (unsigned int)((m_dMaxPeaks*2 + 1)* + (m_dMaxPeaks*2 + 1) * (m_dMaxPeaks*2 + 1)); + //log_info("Number of objects: ", iObjCnt); + + m_pPlot->SetEnabled(0); + m_pPlot->clear(); + m_pPlot->SetObjectCount(iObjCnt); + + unsigned int iPeakIdx = 0; + const t_real dLimMax = std::numeric_limits::max(); + + std::vector vecMin = {dLimMax, dLimMax, dLimMax}, + vecMax = {-dLimMax, -dLimMax, -dLimMax}; + + for(t_real h=-m_dMaxPeaks; h<=m_dMaxPeaks; h+=1.) + for(t_real k=-m_dMaxPeaks; k<=m_dMaxPeaks; k+=1.) + for(t_real l=-m_dMaxPeaks; l<=m_dMaxPeaks; l+=1.) + { + int ih = int(h), ik = int(k), il = int(l); + if(pSpaceGroup) + { + if(!pSpaceGroup->HasReflection(ih, ik, il)) + continue; + } + + bool bInScatteringPlane = 0; + ublas::vector vecPeak = recip.GetPos(h,k,l); + for(unsigned int i=0; i<3; ++i) + { + vecMin[i] = std::min(vecPeak[i], vecMin[i]); + vecMax[i] = std::max(vecPeak[i], vecMax[i]); + } + + t_real dDist = 0.; + ublas::vector vecDropped = plane.GetDroppedPerp(vecPeak, &dDist); + + std::vector vecColor{0., 0., 1., 0.7}; + if(tl::float_equal(dDist, 0., m_dPlaneDistTolerance)) + { + bool bIsDirectBeam = 0; + if(tl::float_equal(h, 0.) && + tl::float_equal(k, 0.) && + tl::float_equal(l, 0.)) + bIsDirectBeam = 1; + + if(bIsDirectBeam) + vecColor = std::vector{0., 1., 0., 0.7}; + else + vecColor = std::vector{1., 0., 0., 0.7}; + + bInScatteringPlane = 1; + } + + m_pPlot->PlotSphere(vecPeak, 0.1, iPeakIdx); + m_pPlot->SetObjectColor(iPeakIdx, vecColor); + + std::ostringstream ostrLab; + ostrLab << "(" << ih << " " << ik << " " << il << ")"; + m_pPlot->SetObjectLabel(iPeakIdx, ostrLab.str()); + + //log_info("Index: ", iPeakIdx); + ++iPeakIdx; + } + + m_pPlot->SetObjectCount(iPeakIdx); // actual count (some peaks forbidden by sg) + m_pPlot->SetMinMax(vecMin, vecMax); + m_pPlot->SetEnabled(1); +} + + +void Recip3DDlg::hideEvent(QHideEvent *event) +{ + if(m_pPlot) m_pPlot->SetEnabled(0); + + //if(m_pSettings) + // m_pSettings->setValue("recip3d/geo", saveGeometry()); +} +void Recip3DDlg::showEvent(QShowEvent *event) +{ + //if(m_pSettings && m_pSettings->contains("recip3d/geo")) + // restoreGeometry(m_pSettings->value("recip3d/geo").toByteArray()); + + if(m_pPlot) m_pPlot->SetEnabled(1); +} + + +#include "recip3d.moc" diff --git a/tools/taz/recip3d.h b/tools/taz/recip3d.h new file mode 100644 index 0000000..78b84f9 --- /dev/null +++ b/tools/taz/recip3d.h @@ -0,0 +1,43 @@ +/* + * Scattering Triangle Tool + * @author tweber + * @date mar-2014 + * @license GPLv2 + */ + +#ifndef __TAZ_RECIP_3D__ +#define __TAZ_RECIP_3D__ + +#include +#include "libs/plotgl.h" +#include "tlibs/math/linalg.h" +#include "tlibs/math/geo.h" +#include "tlibs/math/lattice.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/spacegroups/latticehelper.h" +#include "libs/globals.h" + + +class Recip3DDlg : public QDialog +{Q_OBJECT +protected: + PlotGl* m_pPlot; + t_real_glob m_dMaxPeaks = 5.; + t_real_glob m_dPlaneDistTolerance = 0.01; + +public: + Recip3DDlg(QWidget* pParent, QSettings* = 0); + virtual ~Recip3DDlg(); + + void CalcPeaks(const LatticeCommon& recipcommon); + + void SetPlaneDistTolerance(t_real_glob dTol) { m_dPlaneDistTolerance = dTol; } + void SetMaxPeaks(t_real_glob dMax) { m_dMaxPeaks = dMax; } + +protected: + void hideEvent(QHideEvent*); + void showEvent(QShowEvent*); +}; + + +#endif diff --git a/tools/taz/scattering_triangle.cpp b/tools/taz/scattering_triangle.cpp new file mode 100644 index 0000000..56e6463 --- /dev/null +++ b/tools/taz/scattering_triangle.cpp @@ -0,0 +1,1702 @@ +/** + * Reciprocal Lattice + * @author tweber + * @date 2014 - 2016 + * @license GPLv2 + */ + +#include "tlibs/helper/flags.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/log/log.h" +#include "scattering_triangle.h" + +#include +#include +#include +#include +#include + +using t_real = t_real_glob; +using t_vec = ublas::vector; +using t_mat = ublas::matrix; +static const tl::t_length_si angs = tl::get_one_angstrom(); +static const tl::t_energy_si meV = tl::get_one_meV(); +static const tl::t_angle_si rads = tl::get_one_radian(); + +// symbol drawing sizes +#define DEF_PEAK_SIZE 3. +#define MIN_PEAK_SIZE 0.2 +#define MAX_PEAK_SIZE 5.5 + + +static inline bool flip_text(t_real _dAngle) +{ + t_real dAngle = std::fmod(_dAngle, 360.); + return std::abs(dAngle) > 90. && std::abs(dAngle) < 270.; +} + + +ScatteringTriangleNode::ScatteringTriangleNode(ScatteringTriangle* pSupItem) + : m_pParentItem(pSupItem) +{ + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setCursor(Qt::CrossCursor); + + setData(TRIANGLE_NODE_TYPE_KEY, NODE_OTHER); +} + +QRectF ScatteringTriangleNode::boundingRect() const +{ + return QRectF(-5., -5., 10., 10.); +} + +void ScatteringTriangleNode::paint(QPainter *painter, const QStyleOptionGraphicsItem* popt, QWidget* pwid) +{ + painter->drawEllipse(QRectF(-2., -2., 4., 4.)); +} + +void ScatteringTriangleNode::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + //setCursor(Qt::ClosedHandCursor); + QGraphicsItem::mousePressEvent(pEvt); +} + +void ScatteringTriangleNode::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + //setCursor(Qt::OpenHandCursor); + QGraphicsItem::mouseReleaseEvent(pEvt); +} + +QVariant ScatteringTriangleNode::itemChange(GraphicsItemChange change, const QVariant &val) +{ + QVariant var = QGraphicsItem::itemChange(change, val); + + if(change == QGraphicsItem::ItemPositionHasChanged) + m_pParentItem->nodeMoved(this); + + return var; +} + + +// -------------------------------------------------------------------------------- + +RecipPeak::RecipPeak() +{ + //setCursor(Qt::ArrowCursor); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setFlag(QGraphicsItem::ItemIsMovable, false); +} + +QRectF RecipPeak::boundingRect() const +{ + //return QRectF(-50., -10., 100., 80.); + return QRectF(-35., -10., 70., 50.); +} + +void RecipPeak::paint(QPainter *painter, const QStyleOptionGraphicsItem* pOpt, QWidget* pWid) +{ + painter->setFont(g_fontGfx); + painter->setBrush(m_color); + painter->drawEllipse(QRectF(-m_dRadius, -m_dRadius, m_dRadius*2., m_dRadius*2.)); + + if(m_strLabel != "") + { + painter->setPen(m_color); + QRectF rect = boundingRect(); + rect.setTop(rect.top()+16.5); + //painter->drawRect(rect); + painter->drawText(rect, Qt::AlignHCenter|Qt::AlignTop, m_strLabel); + } +} + +// -------------------------------------------------------------------------------- + + +ScatteringTriangle::ScatteringTriangle(ScatteringTriangleScene& scene) + : m_scene(scene) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + + m_pNodeKiQ = new ScatteringTriangleNode(this); + m_pNodeKiKf = new ScatteringTriangleNode(this); + m_pNodeKfQ = new ScatteringTriangleNode(this); + m_pNodeGq = new ScatteringTriangleNode(this); + + m_pNodeKiQ->setData(TRIANGLE_NODE_TYPE_KEY, NODE_KIQ); + m_pNodeKiKf->setData(TRIANGLE_NODE_TYPE_KEY, NODE_KIKF); + m_pNodeKfQ->setData(TRIANGLE_NODE_TYPE_KEY, NODE_Q); + m_pNodeGq->setData(TRIANGLE_NODE_TYPE_KEY, NODE_q); + + AllowMouseMove(1); + + m_pNodeKiQ->setPos(0., 0.); + m_pNodeKiKf->setPos(80., -150.); + m_pNodeKfQ->setPos(160., 0.); + m_pNodeGq->setPos(160., 0.); + + m_scene.addItem(m_pNodeKiQ); + m_scene.addItem(m_pNodeKiKf); + m_scene.addItem(m_pNodeKfQ); + m_scene.addItem(m_pNodeGq); + + setAcceptedMouseButtons(0); + m_bReady = 1; +} + +ScatteringTriangle::~ScatteringTriangle() +{ + m_bReady = 0; + + delete m_pNodeKiQ; + delete m_pNodeKiKf; + delete m_pNodeKfQ; + delete m_pNodeGq; + + ClearPeaks(); +} + +void ScatteringTriangle::AllowMouseMove(bool bAllow) +{ + m_pNodeKiKf->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pNodeKfQ->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pNodeGq->setFlag(QGraphicsItem::ItemIsMovable, bAllow); +} + +void ScatteringTriangle::nodeMoved(const ScatteringTriangleNode* pNode) +{ + if(!m_bReady) return; + + if(m_scene.getSnapq() && pNode==GetNodeKfQ()) + SnapToNearestPeak(GetNodeGq(), GetNodeKfQ()); + + update(); + m_scene.emitUpdate(); + m_scene.emitAllParams(); +} + +QRectF ScatteringTriangle::boundingRect() const +{ + return QRectF(-1000.*m_dZoom, -1000.*m_dZoom, + 2000.*m_dZoom, 2000.*m_dZoom); +} + +void ScatteringTriangle::SetZoom(t_real dZoom) +{ + m_dZoom = dZoom; + m_scene.update(); +} + +void ScatteringTriangle::SetqVisible(bool bVisible) +{ + m_bqVisible = bVisible; + this->m_pNodeGq->setVisible(bVisible); + this->update(); +} + +void ScatteringTriangle::SetBZVisible(bool bVisible) +{ + m_bShowBZ = bVisible; + this->update(); +} + +void ScatteringTriangle::SetEwaldSphereVisible(EwaldSphere iEw) +{ + m_bShowEwaldSphere = (iEw != EWALD_NONE); + m_bEwaldAroundKi = (iEw == EWALD_KI); + this->update(); +} + +QPointF ScatteringTriangle::GetGfxMid() const +{ + QPointF ptKiQ = mapFromItem(m_pNodeKiQ, 0, 0); + QPointF ptKfQ = mapFromItem(m_pNodeKfQ, 0, 0); + QPointF ptKiKf = mapFromItem(m_pNodeKiKf, 0, 0); + + return (ptKiQ + ptKfQ + ptKiKf) / 3.; +} + +void ScatteringTriangle::paint(QPainter *painter, const QStyleOptionGraphicsItem* pOpt, QWidget* pWid) +{ + painter->setFont(g_fontGfx); + + // Brillouin zone + if(m_bShowBZ && m_bz.IsValid()) + { + QPen penOrg = painter->pen(); + painter->setPen(Qt::lightGray); + + const t_vec& vecCentral = m_bz.GetCentralReflex() * m_dScaleFactor*m_dZoom; + //std::cout << vecCentral << std::endl; + for(const RecipPeak* pPeak : m_vecPeaks) + { + QPointF peakPos = pPeak->pos(); + peakPos *= m_dZoom; + + const tl::Brillouin2D::t_vertices& verts = m_bz.GetVertices(); + for(const tl::Brillouin2D::t_vecpair& vertpair : verts) + { + const t_vec& vec1 = vertpair.first * m_dScaleFactor * m_dZoom; + const t_vec& vec2 = vertpair.second * m_dScaleFactor * m_dZoom; + + QPointF pt1 = vec_to_qpoint(vec1 - vecCentral) + peakPos; + QPointF pt2 = vec_to_qpoint(vec2 - vecCentral) + peakPos; + + QLineF lineBZ(pt1, pt2); + painter->drawLine(lineBZ); + } + } + + painter->setPen(penOrg); + } + + + + QPointF ptKiQ = mapFromItem(m_pNodeKiQ, 0, 0) * m_dZoom; + QPointF ptKfQ = mapFromItem(m_pNodeKfQ, 0, 0) * m_dZoom; + QPointF ptKiKf = mapFromItem(m_pNodeKiKf, 0, 0) * m_dZoom; + QPointF ptGq = mapFromItem(m_pNodeGq, 0, 0) * m_dZoom; + + + + // Powder lines + { + QPen penOrg = painter->pen(); + painter->setPen(Qt::red); + + const typename tl::Powder::t_peaks_unique& powderpeaks = m_powder.GetUniquePeaks(); + for(const typename tl::Powder::t_peak& powderpeak : powderpeaks) + { + const int ih = std::get<0>(powderpeak); + const int ik = std::get<1>(powderpeak); + const int il = std::get<2>(powderpeak); + + if(ih==0 && ik==0 && il==0) continue; + + std::ostringstream ostrPowderLine; + ostrPowderLine << "(" << ih << " "<< ik << " " << il << ")"; + + t_vec vec = m_powder.GetRecipLatticePos(t_real(ih), t_real(ik), t_real(il)); + t_real drad = std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + drad *= m_dScaleFactor*m_dZoom; + + painter->drawEllipse(ptKiQ, drad, drad); + painter->drawText(ptKiQ + QPointF(0., drad), ostrPowderLine.str().c_str()); + } + painter->setPen(penOrg); + } + + + + QPointF ptQMid = ptKiQ + (ptKfQ - ptKiQ)/2.; + QPointF ptKiMid = ptKiQ + (ptKiKf - ptKiQ)/2.; + QPointF ptKfMid = ptKfQ + (ptKiKf - ptKfQ)/2.; + QPointF ptqMid = ptKfQ + (ptGq - ptKfQ)/2.; + QPointF ptGMid = ptKiQ + (ptGq - ptKiQ)/2.; + + QPointF ptMid = ptKiQ + (ptKfQ - ptKiQ)/2.; + ptMid = ptMid + (ptKiKf - ptMid)/2.; + + QLineF lineQ(ptKiQ, ptKfQ); + QLineF lineKi(ptKiQ, ptKiKf); + QLineF lineKf(ptKiKf, ptKfQ); + QLineF lineG(ptKiQ, ptGq); + QLineF lineq(ptKfQ, ptGq); + + painter->setPen(Qt::red); + painter->drawLine(lineQ); + painter->setPen(Qt::black); + painter->drawLine(lineKi); + painter->drawLine(lineKf); + + if(m_bqVisible) + { + QPen penOrg = painter->pen(); + painter->setPen(Qt::darkGreen); + + painter->drawLine(lineG); + painter->drawLine(lineq); + + painter->setPen(penOrg); + } + + const t_real dG = lineG.length()/m_dScaleFactor/m_dZoom; + + const std::wstring strAA = tl::get_spec_char_utf16("AA") + tl::get_spec_char_utf16("sup-") + tl::get_spec_char_utf16("sup1"); + const std::wstring& strDelta = tl::get_spec_char_utf16("Delta"); + + std::wostringstream ostrQ, ostrKi, ostrKf, ostrE, ostrq, ostrG; + ostrQ.precision(g_iPrecGfx); ostrE.precision(g_iPrecGfx); + ostrKi.precision(g_iPrecGfx); ostrKf.precision(g_iPrecGfx); + ostrG.precision(g_iPrecGfx); ostrq.precision(g_iPrecGfx); + + t_real dQ = GetQ(); tl::set_eps_0(dQ, g_dEpsGfx); + t_real dKi = GetKi(); tl::set_eps_0(dKi, g_dEpsGfx); + t_real dKf = GetKf(); tl::set_eps_0(dKf, g_dEpsGfx); + t_real dE = GetE(); tl::set_eps_0(dE, g_dEpsGfx); + + ostrQ << L"Q = " << dQ << " " << strAA; + ostrKi << L"ki = " << dKi << " " << strAA; + ostrKf << L"kf = " << dKf << " " << strAA; + ostrE << strDelta << "E = " << dE << " meV"; + if(m_bqVisible) + { + ostrq << L"q = " << Getq() << " " << strAA; + ostrG << L"G = " << dG << " " << strAA; + } + + painter->save(); + t_real dAngleQ = -lineQ.angle(); + painter->rotate(dAngleQ); + painter->setPen(Qt::red); + painter->translate(QPointF(lineQ.length()/5., 16.)); + if(flip_text(dAngleQ)) + { + painter->translate(QPointF(lineQ.length()/2., -10.)); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrQ.str().c_str())); + painter->restore(); + + painter->save(); + t_real dAngleKi = -lineKi.angle(); + painter->rotate(dAngleKi); + painter->setPen(Qt::black); + painter->translate(QPointF(lineKi.length()/5., -4.)); + if(flip_text(dAngleKi)) + { + painter->translate(QPointF(lineKi.length()/2., -12.)); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrKi.str().c_str())); + painter->restore(); + + painter->save(); + t_real dAngleKf = -lineKf.angle(); + painter->translate(ptKiKf); + painter->rotate(dAngleKf); + painter->translate(QPointF(lineKf.length()/5., -4.)); + if(flip_text(dAngleKf)) + { + painter->translate(QPointF(lineKf.length()/2., 8.)); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrKf.str().c_str())); + painter->drawText(QPointF(0.,16.), QString::fromWCharArray(ostrE.str().c_str())); + painter->restore(); + + if(m_bqVisible) + { + QPen penOrg = painter->pen(); + painter->setPen(Qt::darkGreen); + + painter->save(); + painter->translate(ptKfQ); + painter->rotate(-lineq.angle()); + painter->drawText(QPointF(lineq.length()/5.,-4.), QString::fromWCharArray(ostrq.str().c_str())); + painter->restore(); + + painter->save(); + painter->rotate(-lineG.angle()); + painter->drawText(QPointF(lineG.length()/5.,-4.), QString::fromWCharArray(ostrG.str().c_str())); + painter->rotate(lineG.angle()); + painter->restore(); + + painter->setPen(penOrg); + } + + + QLineF lineKi2(ptKiKf, ptKiQ); + QLineF lineKf2(ptKfQ, ptKiKf); + QLineF lineQ2(ptKfQ, ptKiQ); + + std::vector vecLines1 = {&lineKi2, &lineKi, &lineKf}; + std::vector vecLines2 = {&lineQ, &lineKf, &lineQ2}; + std::vector vecPoints = {&ptKiQ, &ptKiKf, &ptKfQ}; + + std::vector vecLinesArrow = {&lineKi2, &lineKf, &lineQ2}; + std::vector vecPointsArrow = {&ptKiKf, &ptKiKf, &ptKfQ}; + + std::vector vecDrawAngles = {1,1,1}; + std::vector vecColor {Qt::black, Qt::black, Qt::red}; + + QLineF lineG2(ptGq, ptKiQ); + QLineF lineq2(ptGq, ptKfQ); + + if(m_bqVisible) + { + vecLinesArrow.push_back(&lineq); + vecLinesArrow.push_back(&lineG2); + + vecPointsArrow.push_back(&ptKfQ); + vecPointsArrow.push_back(&ptGq); + + vecDrawAngles.push_back(0); + vecDrawAngles.push_back(0); + + vecColor.push_back(Qt::darkGreen); + vecColor.push_back(Qt::darkGreen); + } + + + const std::wstring& strDEG = tl::get_spec_char_utf16("deg"); + + for(std::size_t i=0; iangle() + 90.); + t_real dC = std::cos(dAng); + t_real dS = std::sin(dAng); + + t_real dTriagX = 5., dTriagY = 10.; + QPointF ptTriag1 = *vecPointsArrow[i] + QPointF(dTriagX*dC + dTriagY*dS, -dTriagX*dS + dTriagY*dC); + QPointF ptTriag2 = *vecPointsArrow[i] + QPointF(-dTriagX*dC + dTriagY*dS, dTriagX*dS + dTriagY*dC); + + QPainterPath triag; + triag.moveTo(*vecPointsArrow[i]); + triag.lineTo(ptTriag1); + triag.lineTo(ptTriag2); + + painter->setPen(vecColor[i]); + painter->fillPath(triag, vecColor[i]); + + if(vecDrawAngles[i]) + { + // angle arcs + t_real dArcSize = (vecLines1[i]->length() + vecLines2[i]->length()) / 2. / 3.; + t_real dBeginArcAngle = vecLines1[i]->angle() + 180.; + t_real dArcAngle = vecLines1[i]->angleTo(*vecLines2[i]) - 180.; + + painter->setPen(Qt::blue); + painter->drawArc(QRectF(vecPoints[i]->x()-dArcSize/2., vecPoints[i]->y()-dArcSize/2., + dArcSize, dArcSize), dBeginArcAngle*16., dArcAngle*16.); + + std::wostringstream ostrAngle; + ostrAngle.precision(g_iPrecGfx); + ostrAngle << std::fabs(dArcAngle) << strDEG; + + + t_real dTotalAngle = -dBeginArcAngle-dArcAngle*0.5 + 180.; + t_real dTransScale = 50. * m_dZoom; + painter->save(); + painter->translate(*vecPoints[i]); + painter->rotate(dTotalAngle); + painter->translate(-dTransScale, +4.); + if(flip_text(dTotalAngle)) + { + painter->translate(dTransScale*0.5, -8.); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrAngle.str().c_str())); + painter->restore(); + + } + } + + + // Ewald sphere + if(m_bShowEwaldSphere) + { + t_real dKLen = m_bEwaldAroundKi ? lineKi.length() : lineKf.length(); + painter->setPen(Qt::darkCyan); + painter->drawEllipse(ptKiKf, dKLen, dKLen); + } +} + +t_real ScatteringTriangle::GetKi() const +{ + QPointF ptKiQ = mapFromItem(m_pNodeKiQ, 0, 0); + QPointF ptKiKf = mapFromItem(m_pNodeKiKf, 0, 0); + + QLineF lineKi(ptKiQ, ptKiKf); + const t_real dKi = lineKi.length()/m_dScaleFactor; + return dKi; +} + +t_real ScatteringTriangle::GetKf() const +{ + QPointF ptKfQ = mapFromItem(m_pNodeKfQ, 0, 0); + QPointF ptKiKf = mapFromItem(m_pNodeKiKf, 0, 0); + + QLineF lineKf(ptKiKf, ptKfQ); + const t_real dKf = lineKf.length()/m_dScaleFactor; + return dKf; +} + +t_real ScatteringTriangle::GetE() const +{ + const t_real dKi = GetKi(); + const t_real dKf = GetKf(); + const t_real dE = tl::get_energy_transfer(dKi/angs, dKf/angs) / meV; + return dE; +} + +t_real ScatteringTriangle::GetQ() const +{ + QPointF ptKiQ = mapFromItem(m_pNodeKiQ, 0, 0) * m_dZoom; + QPointF ptKfQ = mapFromItem(m_pNodeKfQ, 0, 0) * m_dZoom; + + QLineF lineQ(ptKiQ, ptKfQ); + const t_real dQ = lineQ.length()/m_dScaleFactor/m_dZoom; + return dQ; +} + +t_real ScatteringTriangle::Getq() const +{ + QPointF ptKfQ = mapFromItem(m_pNodeKfQ, 0, 0) * m_dZoom; + QPointF ptGq = mapFromItem(m_pNodeGq, 0, 0) * m_dZoom; + + QLineF lineq(ptKfQ, ptGq); + const t_real dq = lineq.length()/m_dScaleFactor/m_dZoom; + return dq; +} + +t_real ScatteringTriangle::GetAngleQVec0() const +{ + t_vec vecQ = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)); + vecQ /= ublas::norm_2(vecQ); + vecQ = -vecQ; + + // TODO: Q is in rlu! check angle for non-cubic case! + return tl::vec_angle(vecQ); +} + +t_real ScatteringTriangle::GetAngleKiQ(bool bPosSense) const +{ + /*t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + vecKi /= ublas::norm_2(vecKi); + + const t_real dAngle = vec_angle(vecKi) - GetAngleQVec0();*/ + + try + { + t_real dTT = GetTwoTheta(bPosSense); + t_real dAngle = tl::get_angle_ki_Q(GetKi()/angs, GetKf()/angs, GetQ()/angs, bPosSense) / rads; + //std::cout << "tt=" << dTT << ", kiQ="< tl::get_pi()) + dAngle = -dAngle; + + return dAngle; + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + return 0.; + } +} + +t_real ScatteringTriangle::GetAngleKfQ(bool bPosSense) const +{ + /*t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + vecKf /= ublas::norm_2(vecKf); + + const t_real dAngle = vec_angle(vecKf) - GetAngleQVec0();*/ + + try + { + t_real dTT = GetTwoTheta(bPosSense); + t_real dAngle = tl::get_pi()-tl::get_angle_kf_Q(GetKi()/angs, GetKf()/angs, GetQ()/angs, bPosSense) / rads; + + if(std::fabs(dTT) > tl::get_pi()) + dAngle = -dAngle; + + return dAngle; + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + return 0.; + } +} + +t_real ScatteringTriangle::GetTheta(bool bPosSense) const +{ + t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + vecKi /= ublas::norm_2(vecKi); + + t_real dTh = tl::vec_angle(vecKi) - tl::get_pi()/2.; + //dTh += m_dAngleRot; + if(!bPosSense) + dTh = -dTh; + + //tl::log_info("theta: ", dTh/M_PI*180.); + return dTh; +} + +t_real ScatteringTriangle::GetTwoTheta(bool bPosSense) const +{ + t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + + vecKi /= ublas::norm_2(vecKi); + vecKf /= ublas::norm_2(vecKf); + + t_real dTT = tl::vec_angle(vecKi) - tl::vec_angle(vecKf); + if(dTT < 0.) + dTT += 2.*tl::get_pi(); + dTT = std::fmod(dTT, 2.*tl::get_pi()); + + if(!bPosSense) + dTT = -dTT; + + return dTT; +} + +t_real ScatteringTriangle::GetMonoTwoTheta(t_real dMonoD, bool bPosSense) const +{ + t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ, 0, 0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf, 0, 0)); + t_real dKi = ublas::norm_2(vecKi) / m_dScaleFactor; + return tl::get_mono_twotheta(dKi/angs, dMonoD*angs, bPosSense) / rads; +} + +t_real ScatteringTriangle::GetAnaTwoTheta(t_real dAnaD, bool bPosSense) const +{ + t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ, 0, 0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf, 0, 0)); + t_real dKf = ublas::norm_2(vecKf) / m_dScaleFactor; + return tl::get_mono_twotheta(dKf/angs, dAnaD*angs, bPosSense) / rads; +} + +void ScatteringTriangle::SetAnaTwoTheta(t_real dTT, t_real dAnaD) +{ + dTT = std::fabs(dTT); + t_real dKf = tl::get_pi() / std::sin(dTT/2.) / dAnaD; + dKf *= m_dScaleFactor; + + const t_vec vecNodeKiKf = qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + const t_vec vecNodeKfQ = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)); + t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)) + - vecNodeKiKf; + + vecKf /= ublas::norm_2(vecKf); + t_vec vecKf_new = vecKf * dKf; + + m_pNodeKfQ->setPos(vec_to_qpoint(vecNodeKiKf + vecKf_new)); + nodeMoved(m_pNodeKfQ); +} + +void ScatteringTriangle::SetMonoTwoTheta(t_real dTT, t_real dMonoD) +{ + const t_real dSampleTT = GetTwoTheta(1); + + dTT = std::fabs(dTT); + t_real dKi = tl::get_pi() / std::sin(dTT/2.) / dMonoD; + dKi *= m_dScaleFactor; + + const t_vec vecNodeKiKf = qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + const t_vec vecNodeKiQ = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)); + const t_vec vecKi_old = qpoint_to_vec(mapFromItem(m_pNodeKiQ, 0, 0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf, 0, 0)); + + t_vec vecKi = vecKi_old; + vecKi /= ublas::norm_2(vecKi); + t_vec vecKi_new = vecKi * dKi; + + m_pNodeKiKf->setPos(vec_to_qpoint(vecNodeKiQ - vecKi_new)); + nodeMoved(m_pNodeKiKf); + + SetTwoTheta(dSampleTT); // m_pNodeKfQ also moved! +} + +void ScatteringTriangle::SetTwoTheta(t_real dTT) +{ + const t_vec vecNodeKiKf = qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + const t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + const t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)) + - vecNodeKiKf; + + t_vec vecKf_new = ublas::prod(tl::rotation_matrix_2d(-dTT), vecKi); + + vecKf_new /= ublas::norm_2(vecKf_new); + vecKf_new *= ublas::norm_2(vecKf); + + m_pNodeKfQ->setPos(vec_to_qpoint(vecNodeKiKf + vecKf_new)); + nodeMoved(m_pNodeKfQ); +} + +void ScatteringTriangle::RotateKiVec0To(bool bSense, t_real dAngle) +{ + t_real dAngleCorr = bSense ? -tl::get_pi()/2. : tl::get_pi()/2.; + t_real dCurAngle = GetTheta(bSense) + dAngleCorr; + if(bSense) dCurAngle = -dCurAngle; + //std::cout << "old: " << dCurAngle/M_PI*180. << "new: " << dAngle/M_PI*180. << std::endl; + + t_vec vecNodeKiKf = qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + t_vec vecNodeKfQ = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)); + + t_mat matRot = tl::rotation_matrix_2d(dCurAngle - dAngle); + vecNodeKiKf = ublas::prod(matRot, vecNodeKiKf); + vecNodeKfQ = ublas::prod(matRot, vecNodeKfQ); + + m_pNodeKiKf->setPos(vec_to_qpoint(vecNodeKiKf)); + m_pNodeKfQ->setPos(vec_to_qpoint(vecNodeKfQ)); + + nodeMoved(m_pNodeKiKf); + nodeMoved(m_pNodeKfQ); +} + +void ScatteringTriangle::CalcPeaks(const LatticeCommon& recipcommon, bool bIsPowder) +{ + ClearPeaks(); + m_powder.clear(); + m_kdLattice.Unload(); + + m_lattice = recipcommon.lattice; + m_recip = recipcommon.recip; + m_matPlane = recipcommon.matPlane; + m_matPlane_inv = recipcommon.matPlane_inv; + + m_powder.SetRecipLattice(&m_recip); + + + // ------------------------------------------------------------------------- + // central peak for BZ calculation + //const int iCent[] = {0,0,0}; + + std::vector> vecPeaksToTry = + { + std::make_tuple(1, 2), std::make_tuple(1, 3), std::make_tuple(1, 4), std::make_tuple(1, 5), std::make_tuple(1, 6), + std::make_tuple(2, 1), std::make_tuple(2, 3), std::make_tuple(2, 4), std::make_tuple(2, 5), std::make_tuple(2, 6), + std::make_tuple(3, 1), std::make_tuple(3, 2), std::make_tuple(3, 4), std::make_tuple(3, 5), std::make_tuple(3, 6), + }; + + ublas::vector veciCent; + for(const std::tuple& tup : vecPeaksToTry) + { + veciCent.clear(); + + t_vec vecdCent = std::get<0>(tup) * recipcommon.dir0RLU + + std::get<1>(tup) * recipcommon.dir1RLU; + veciCent = tl::convert_vec(vecdCent); + if(recipcommon.pSpaceGroup && + !recipcommon.pSpaceGroup->HasReflection(veciCent[0], veciCent[1], veciCent[2])) + continue; + break; + } + //std::cout << veciCent << std::endl; + + if(!veciCent.size()) + veciCent = tl::make_vec({0.,0.,0.}); + // ------------------------------------------------------------------------- + + + // crystal rotation angle + /*try + { + t_vec vecUnrotX = plane.GetDroppedPerp(m_recip_unrot.GetVec(0)); + t_vec vecRotX = plane.GetDroppedPerp(m_recip.GetVec(0)); + + const t_vec &vecNorm = plane.GetNorm(); + m_dAngleRot = -tl::vec_angle(vecRotX, vecUnrotX, &vecNorm); + + //std::cout << "rotation angle: " << m_dAngleRot/M_PI*180. << std::endl; + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + return; + }*/ + + + //const t_mat matB = recip.GetMetric(); + + const std::string strAA = tl::get_spec_char_utf8("AA") + + tl::get_spec_char_utf8("sup-") + + tl::get_spec_char_utf8("sup1"); + std::list> lstPeaksForKd; + t_real dMinF = std::numeric_limits::max(), dMaxF = -1.; + + for(int ih=-m_iMaxPeaks; ih<=m_iMaxPeaks; ++ih) + for(int ik=-m_iMaxPeaks; ik<=m_iMaxPeaks; ++ik) + for(int il=-m_iMaxPeaks; il<=m_iMaxPeaks; ++il) + { + const t_real h = t_real(ih); + const t_real k = t_real(ik); + const t_real l = t_real(il); + + if(recipcommon.pSpaceGroup) + { + if(!recipcommon.pSpaceGroup->HasReflection(ih, ik, il)) + continue; + } + + + t_vec vecPeak = m_recip.GetPos(h,k,l); + //t_vec vecPeak = matB * tl::make_vec({h,k,l}); + //const t_real dG = ublas::norm_2(vecPeak); + + + if(bIsPowder) + m_powder.AddPeak(ih, ik, il); + + // (000), i.e. direct beam, also needed for powder + if(!bIsPowder || (ih==0 && ik==0 && il==0)) + { + // add peak in 1/A and rlu units + lstPeaksForKd.push_back(std::vector + { vecPeak[0],vecPeak[1],vecPeak[2], h,k,l/*, dF*/ }); + + t_real dDist = 0.; + t_vec vecDropped = recipcommon.plane.GetDroppedPerp(vecPeak, &dDist); + + if(tl::float_equal(dDist, 0., m_dPlaneDistTolerance)) + { + t_vec vecCoord = ublas::prod(m_matPlane_inv, vecDropped); + t_real dX = vecCoord[0]; + t_real dY = -vecCoord[1]; + + t_real dF = -1.; + std::string strStructfact; + + // -------------------------------------------------------------------- + // structure factors + if(recipcommon.CanCalcStructFact()) + { + t_real dFsq; + std::tie(std::ignore, dF, dFsq) = + recipcommon.GetStructFact(vecPeak); + + //dFsq *= tl::lorentz_factor(dAngle); + tl::set_eps_0(dFsq, g_dEpsGfx); + + tl::set_eps_0(dF, g_dEpsGfx); + dMinF = std::min(dF, dMinF); + dMaxF = std::max(dF, dMaxF); + + std::ostringstream ostrStructfact; + ostrStructfact.precision(g_iPrecGfx); + if(g_bShowFsq) + ostrStructfact << "S = " << dFsq; + else + ostrStructfact << "F = " << dF; + strStructfact = ostrStructfact.str(); + } + // -------------------------------------------------------------------- + + + RecipPeak *pPeak = new RecipPeak(); + if(ih==0 && ik==0 && il==0) + pPeak->SetColor(Qt::green); + pPeak->setPos(dX * m_dScaleFactor, dY * m_dScaleFactor); + if(dF >= 0.) pPeak->SetRadius(dF); + pPeak->setData(TRIANGLE_NODE_TYPE_KEY, NODE_BRAGG); + + std::ostringstream ostrLabel, ostrTip; + ostrLabel.precision(g_iPrecGfx); + ostrTip.precision(g_iPrecGfx); + + ostrLabel << "(" << ih << " " << ik << " " << il << ")"; + ostrTip << "(" << ih << " " << ik << " " << il << ") rlu"; + if(strStructfact.length()) + { + ostrLabel << "\n" << strStructfact; + ostrTip << "\n" << strStructfact << " fm"; + } + + if(ih!=0 || ik!=0 || il!=0) + pPeak->SetLabel(ostrLabel.str().c_str()); + + tl::set_eps_0(vecPeak); + ostrTip << "\n(" + << vecPeak[0] << ", " + << vecPeak[1] << ", " + << vecPeak[2] << ") " << strAA; + + //ostrTip << "\ndistance to plane: " << dDist << " " << strAA; + pPeak->setToolTip(QString::fromUtf8(ostrTip.str().c_str(), ostrTip.str().length())); + + m_vecPeaks.push_back(pPeak); + m_scene.addItem(pPeak); + + + // 1st BZ + if(ih==veciCent[0] && ik==veciCent[1] && il==veciCent[2]) + { + t_vec vecCentral = tl::make_vec({dX, dY}); + //tl::log_debug("Central ", ih, ik, il, ": ", vecCentral); + m_bz.SetCentralReflex(vecCentral); + } + // TODO: check if 2 next neighbours is sufficient for all space groups + else if(std::abs(ih-veciCent[0]) <= 2 + && std::abs(ik-veciCent[1]) <= 2 + && std::abs(il-veciCent[2]) <= 2) + { + t_vec vecN = tl::make_vec({dX, dY}); + //tl::log_debug("Reflex: ", vecN); + m_bz.AddReflex(vecN); + } + } + } + } + + if(!bIsPowder) + { + //for(const auto& vec : m_bz.GetNeighbours()) std::cout << vec << std::endl; + m_bz.CalcBZ(); + //for(RecipPeak* pPeak : m_vecPeaks) + // pPeak->SetBZ(&m_bz); + + m_kdLattice.Load(lstPeaksForKd, 3); + } + + if(dMaxF >= 0.) + { + for(RecipPeak *pPeak : m_vecPeaks) + { + if(!tl::float_equal(dMinF, dMaxF, g_dEpsGfx)) + { + t_real dFScale = (pPeak->GetRadius()-dMinF) / (dMaxF-dMinF); + pPeak->SetRadius(tl::lerp(MIN_PEAK_SIZE, MAX_PEAK_SIZE, dFScale)); + } + else + { + pPeak->SetRadius(DEF_PEAK_SIZE); + } + } + } + + m_scene.emitAllParams(); + this->update(); +} + +t_vec ScatteringTriangle::GetHKLFromPlanePos(t_real x, t_real y) const +{ + if(!HasPeaks()) + return t_vec(); + + t_vec vec = x*tl::get_column(m_matPlane, 0) + + y*tl::get_column(m_matPlane, 1); + return m_recip.GetHKL(vec); +} + +t_vec ScatteringTriangle::GetQVecPlane(bool bSmallQ) const +{ + t_vec vecQPlane; + + if(bSmallQ) + vecQPlane = qpoint_to_vec(mapFromItem(m_pNodeGq,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKfQ, 0, 0)); + else + vecQPlane = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)); + + vecQPlane[1] = -vecQPlane[1]; + vecQPlane /= m_dScaleFactor; + + return vecQPlane; +} + +t_vec ScatteringTriangle::GetQVec(bool bSmallQ, bool bRLU) const +{ + t_vec vecQPlane = GetQVecPlane(bSmallQ); + + t_vec vecQ; + if(bRLU) + vecQ = GetHKLFromPlanePos(vecQPlane[0], vecQPlane[1]); + else + vecQ = vecQPlane[0]*tl::get_column(m_matPlane, 0) + + vecQPlane[1]*tl::get_column(m_matPlane, 1); + + return vecQ; +} + +t_vec ScatteringTriangle::GetKiVecPlane() const +{ + t_vec vecKi = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + vecKi[1] = -vecKi[1]; + vecKi /= m_dScaleFactor; + return vecKi; +} + +t_vec ScatteringTriangle::GetKfVecPlane() const +{ + t_vec vecKf = qpoint_to_vec(mapFromItem(m_pNodeKfQ,0,0)) + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + vecKf[1] = -vecKf[1]; + vecKf /= m_dScaleFactor; + return vecKf; +} + +void ScatteringTriangle::ClearPeaks() +{ + m_bz.Clear(); + + for(RecipPeak*& pPeak : m_vecPeaks) + { + if(pPeak) + { + m_scene.removeItem(pPeak); + delete pPeak; + pPeak = 0; + } + } + m_vecPeaks.clear(); +} + + +std::vector ScatteringTriangle::GetNodes() +{ + return std::vector + { m_pNodeKiQ, m_pNodeKiKf, m_pNodeKfQ, m_pNodeGq }; +} + +std::vector ScatteringTriangle::GetNodeNames() const +{ + return std::vector{ "kiQ", "kikf", "kfQ", "Gq" }; +} + + +static std::pair +get_nearest_elastic_kikf_pos(const QPointF& ptKiKf, const QPointF& ptKiQ, const QPointF& ptKfQ) +{ + std::pair pairRet; + bool& bOk = pairRet.first; + QPointF& ptRet = pairRet.second; + + t_vec vecKiQ = qpoint_to_vec(ptKiQ); + t_vec vecKfQ = qpoint_to_vec(ptKfQ); + t_vec vecKiKf = qpoint_to_vec(ptKiKf); + t_vec vecQ = vecKfQ - vecKiQ; + + t_vec vecQperp = tl::make_vec({vecQ[1], -vecQ[0]}); + t_vec vecQMid = vecKiQ + vecQ*0.5; + + tl::Line lineQMidPerp(vecQMid, vecQperp); + t_vec vecDrop = lineQMidPerp.GetDroppedPerp(vecKiKf); + ptRet = vec_to_qpoint(vecDrop); + + bOk = 1; + return pairRet; +} + + +static std::tuple +get_nearest_node(const QPointF& pt, + const QGraphicsItem* pCurItem, const QList& nodes, + t_real dFactor, const tl::Powder* pPowder=nullptr) +{ + if(nodes.size()==0) + return std::tuple(0, 0., QPointF()); + + t_real dMinLen = std::numeric_limits::max(); + int iMinIdx = -1; + bool bHasPowderPeak = 0; + + // Bragg peaks + for(int iNode=0; iNodedata(TRIANGLE_NODE_TYPE_KEY)!=NODE_BRAGG) + continue; + + t_real dLen = QLineF(pt, pNode->scenePos()).length(); + if(dLen < dMinLen) + { + dMinLen = dLen; + iMinIdx = iNode; + } + } + + const QGraphicsItem* pNodeOrigin = nullptr; + for(const QGraphicsItem* pNode : nodes) + if(pNode->data(TRIANGLE_NODE_TYPE_KEY) == NODE_KIQ) + { + pNodeOrigin = pNode; + break; + } + + + + // Powder peaks + QPointF ptPowder; + if(pNodeOrigin && pPowder) + { + t_vec vecOrigin = qpoint_to_vec(pNodeOrigin->scenePos()); + t_vec vecPt = qpoint_to_vec(pt); + t_vec vecOriginPt = vecPt-vecOrigin; + const t_real dDistToOrigin = ublas::norm_2(vecOriginPt); + vecOriginPt /= dDistToOrigin; + + const typename tl::Powder::t_peaks_unique& powderpeaks = pPowder->GetUniquePeaks(); + for(const typename tl::Powder::t_peak& powderpeak : powderpeaks) + { + const int ih = std::get<0>(powderpeak); + const int ik = std::get<1>(powderpeak); + const int il = std::get<2>(powderpeak); + if(ih==0 && ik==0 && il==0) continue; + + t_vec vec = pPowder->GetRecipLatticePos(t_real(ih), t_real(ik), t_real(il)); + t_real drad = std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + drad *= dFactor; + + if(std::fabs(drad-dDistToOrigin) < dMinLen) + { + bHasPowderPeak = 1; + dMinLen = std::fabs(drad-dDistToOrigin); + + t_vec vecPowder = vecOrigin + vecOriginPt*drad; + ptPowder = vec_to_qpoint(vecPowder); + } + } + } + + + + if(bHasPowderPeak) + { + return std::tuple(1, dMinLen, ptPowder); + } + else + { + if(iMinIdx < 0) + return std::tuple(0, 0., QPointF()); + + return std::tuple(1, dMinLen, nodes[iMinIdx]->pos()); + } +} + +// snap pNode to a peak near pNodeOrg +void ScatteringTriangle::SnapToNearestPeak(ScatteringTriangleNode* pNode, + const ScatteringTriangleNode* pNodeOrg) +{ + if(!pNode) return; + if(!pNodeOrg) pNodeOrg = pNode; + + std::tuple tupNearest = + get_nearest_node(pNodeOrg->pos(), pNode, m_scene.items(), + GetScaleFactor(), &GetPowder()); + + if(std::get<0>(tupNearest)) + pNode->setPos(std::get<2>(tupNearest)); +} + +bool ScatteringTriangle::KeepAbsKiKf(t_real dQx, t_real dQy) +{ + try + { + t_vec vecCurKfQ = tl::make_vec({ + m_pNodeKfQ->scenePos().x(), + m_pNodeKfQ->scenePos().y() }); + + t_vec vecNewKfQ = tl::make_vec({ + m_pNodeKfQ->scenePos().x() + dQx, + m_pNodeKfQ->scenePos().y() + dQy }); + + t_vec vecKiQ = qpoint_to_vec(mapFromItem(m_pNodeKiQ,0,0)); + t_vec vecKi = vecKiQ + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + + t_vec vecKf = vecCurKfQ + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + t_vec vecNewKf = vecNewKfQ + - qpoint_to_vec(mapFromItem(m_pNodeKiKf,0,0)); + + t_vec vecCurQ = vecKiQ - vecCurKfQ; + t_vec vecNewQ = vecKiQ - vecNewKfQ; + + t_real dKi = ublas::norm_2(vecKi)/m_dScaleFactor; + t_real dKf = ublas::norm_2(vecKf)/m_dScaleFactor; + //t_real dCurQ = ublas::norm_2(vecCurQ)/m_dScaleFactor; + t_real dNewQ = ublas::norm_2(vecNewQ)/m_dScaleFactor; + + //t_real dCurAngKiQ = tl::get_angle_ki_Q(dKi/angs, dKf/angs, dCurQ/angs) / tl::radians; + t_real dAngKiQ = tl::get_angle_ki_Q(dKi/angs, dKf/angs, dNewQ/angs) / tl::radians; + + t_mat matRot = tl::rotation_matrix_2d(-dAngKiQ); + vecKi = ublas::prod(matRot, vecNewQ) / ublas::norm_2(vecNewQ); + vecKi *= dKi * m_dScaleFactor; + t_vec vecPtKiKf = vecKiQ - vecKi; + + /*t_vec vecKfChk = vecNewKfQ - vecPtKiKf; + t_real dKfChk = ublas::norm_2(vecKfChk) / m_dScaleFactor; + if(!tl::float_equal(dKfChk, dKf)) + return 0;*/ + + m_bReady = 0; + m_pNodeKiKf->setPos(vec_to_qpoint(vecPtKiKf)); + m_bReady = 1; + + return 1; // allowed + } + catch(const std::exception&) + { + return 0; // not allowed + } +} + +// -------------------------------------------------------------------------------- + + +ScatteringTriangleScene::ScatteringTriangleScene(QObject* pParent) + : QGraphicsScene(pParent), m_pTri(0) +{ + m_pTri = new ScatteringTriangle(*this); + this->addItem(m_pTri); +} + +ScatteringTriangleScene::~ScatteringTriangleScene() +{ + delete m_pTri; +} + +void ScatteringTriangleScene::SetDs(t_real dMonoD, t_real dAnaD) +{ + m_dMonoD = dMonoD; + m_dAnaD = dAnaD; + + emitUpdate(); +} + +void ScatteringTriangleScene::emitUpdate() +{ + if(!m_pTri || !m_pTri->IsReady() || m_bDontEmitChange) + return; + + TriangleOptions opts; + opts.bChangedMonoTwoTheta = 1; + opts.bChangedAnaTwoTheta = 1; + opts.bChangedTwoTheta = 1; + opts.bChangedTheta = 1; + opts.dTwoTheta = m_pTri->GetTwoTheta(m_bSamplePosSense); + opts.dTheta = m_pTri->GetTheta(m_bSamplePosSense); + opts.dAnaTwoTheta = m_pTri->GetAnaTwoTheta(m_dAnaD, m_bAnaPosSense); + opts.dMonoTwoTheta = m_pTri->GetMonoTwoTheta(m_dMonoD, m_bMonoPosSense); + + //tl::log_debug("triangle: triangleChanged"); + emit triangleChanged(opts); +} + +void ScatteringTriangleScene::emitAllParams() +{ + if(!m_pTri || !m_pTri->IsReady() /*|| m_bDontEmitChange*/) // emit even with m_bDontEmitChange because of Q vector in real space + return; + + RecipParams parms; + parms.d2Theta = m_pTri->GetTwoTheta(m_bSamplePosSense); + parms.dTheta = m_pTri->GetTheta(m_bSamplePosSense); + parms.dE = m_pTri->GetE(); + parms.dQ = m_pTri->GetQ(); + parms.dq = m_pTri->Getq(); + parms.dki = m_pTri->GetKi(); + parms.dkf = m_pTri->GetKf(); + parms.dKiQ = m_pTri->GetAngleKiQ(m_bSamplePosSense); + parms.dKfQ = m_pTri->GetAngleKfQ(m_bSamplePosSense); + parms.dAngleQVec0 = m_pTri->GetAngleQVec0(); + + t_vec vecQ = m_pTri->GetQVec(0,0); + t_vec vecQrlu = m_pTri->GetQVec(0,1); + t_vec vecq = m_pTri->GetQVec(1,0); + t_vec vecqrlu = m_pTri->GetQVec(1,1); + t_vec vecG = vecQ - vecq; + t_vec vecGrlu = vecQrlu - vecqrlu; + + const t_mat& matPlane = m_pTri->GetPlane(); + t_vec vec0 = tl::get_column(matPlane, 0); + t_vec vec1 = tl::get_column(matPlane, 1); + t_vec vecUp = tl::get_column(matPlane, 2); + + tl::set_eps_0(vecQ, g_dEps); tl::set_eps_0(vecQrlu, g_dEps); + tl::set_eps_0(vecq, g_dEps); tl::set_eps_0(vecqrlu, g_dEps); + tl::set_eps_0(vecG, g_dEps); tl::set_eps_0(vecGrlu, g_dEps); + + /*std::cout << "Q = " << vecQrlu << std::endl; + std::cout << "q = " << vecqrlu << std::endl; + std::cout << "G = " << vecGrlu << std::endl;*/ + + for(unsigned int i=0; i<3; ++i) + { + parms.Q[i] = vecQ[i]; + parms.Q_rlu[i] = vecQrlu[i]; + + parms.q[i] = vecq[i]; + parms.q_rlu[i] = vecqrlu[i]; + + parms.G[i] = vecG[i]; + parms.G_rlu[i] = vecGrlu[i]; + + parms.orient_0[i] = vec0[i]; + parms.orient_1[i] = vec1[i]; + parms.orient_up[i] = vecUp[i]; + } + + + // nearest node (exact G) + parms.G_rlu_accurate[0] = parms.G_rlu_accurate[1] = parms.G_rlu_accurate[2] = 0.; + const tl::Kd& kd = m_pTri->GetKdLattice(); + t_vec vecHKLinvA = m_pTri->GetRecipLattice().GetPos(-vecQrlu[0], -vecQrlu[1], -vecQrlu[2]); + + if(kd.GetRootNode()) + { + std::vector stdvecHKL{vecHKLinvA[0], vecHKLinvA[1], vecHKLinvA[2]}; + const std::vector* pvecNearest = &kd.GetNearestNode(stdvecHKL); + + if(pvecNearest) + { + parms.G_rlu_accurate[0] = (*pvecNearest)[3]; + parms.G_rlu_accurate[1] = (*pvecNearest)[4]; + parms.G_rlu_accurate[2] = (*pvecNearest)[5]; + } + } + + + CheckForSpurions(); + + //tl::log_debug("triangle: emitAllParams"); + emit paramsChanged(parms); +} + +// check for spurions +void ScatteringTriangleScene::CheckForSpurions() +{ + typedef tl::t_energy_si energy; + + const t_vec vecq = m_pTri->GetQVecPlane(1); + const t_vec vecKi = m_pTri->GetKiVecPlane(); + const t_vec vecKf = m_pTri->GetKfVecPlane(); + energy E = m_pTri->GetE() * meV; + energy Ei = tl::k2E(m_pTri->GetKi()/angs); + energy Ef = tl::k2E(m_pTri->GetKf()/angs); + + // elastic currat-axe spurions + tl::ElasticSpurion spuris = tl::check_elastic_spurion(vecKi, vecKf, vecq); + + // inelastic higher-order spurions + std::vector> vecInelCKI = tl::check_inelastic_spurions(1, Ei, Ef, E, 5); + std::vector> vecInelCKF = tl::check_inelastic_spurions(0, Ei, Ef, E, 5); + + emit spurionInfo(spuris, vecInelCKI, vecInelCKF); +} + +void ScatteringTriangleScene::tasChanged(const TriangleOptions& opts) +{ + if(!m_pTri || !m_pTri->IsReady()) + return; + + m_bDontEmitChange = 1; + + if(opts.bChangedMonoTwoTheta) + { + m_pTri->SetMonoTwoTheta(opts.dMonoTwoTheta, m_dMonoD); + + //log_info("triag, changed mono: ", opts.dMonoTwoTheta/M_PI*180.); + //log_info("triag, mono now: ", m_pTri->GetMonoTwoTheta(3.355, 1)/M_PI*180.); + } + if(opts.bChangedAnaTwoTheta) + { + m_pTri->SetAnaTwoTheta(opts.dAnaTwoTheta, m_dAnaD); + //log_info("triag, changed ana: ", opts.dAnaTwoTheta/M_PI*180.); + //log_info("triag, ana now: ", m_pTri->GetAnaTwoTheta(3.355, 1)/M_PI*180.); + } + + if(opts.bChangedTwoTheta) + { + m_pTri->SetTwoTheta(m_bSamplePosSense?opts.dTwoTheta:-opts.dTwoTheta); + //log_info("triag, changed sample tt: ", opts.dTwoTheta/M_PI*180.); + //log_info("triag, tt now: ", m_pTri->GetTwoTheta(1)/M_PI*180.); + } + if(opts.bChangedAngleKiVec0) + m_pTri->RotateKiVec0To(m_bSamplePosSense, opts.dAngleKiVec0); + + m_bDontEmitChange = 0; +} + +void ScatteringTriangleScene::SetSampleSense(bool bPos) +{ + m_bSamplePosSense = bPos; + emitUpdate(); + emitAllParams(); +} + +void ScatteringTriangleScene::SetMonoSense(bool bPos) +{ + m_bMonoPosSense = bPos; + emitUpdate(); + emitAllParams(); +} + +void ScatteringTriangleScene::SetAnaSense(bool bPos) +{ + m_bAnaPosSense = bPos; + emitUpdate(); + emitAllParams(); +} + +void ScatteringTriangleScene::scaleChanged(t_real dTotalScale) +{ + if(!m_pTri) return; + m_pTri->SetZoom(dTotalScale); +} + +void ScatteringTriangleScene::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 1; + QGraphicsScene::mousePressEvent(pEvt); + emit nodeEvent(1); +} + +void ScatteringTriangleScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + m_bMousePressed = 0; + QGraphicsScene::mouseReleaseEvent(pEvt); + emit nodeEvent(0); +} + +void ScatteringTriangleScene::setSnapq(bool bSnap) +{ + m_bSnapq = bSnap; + + if(m_bSnapq && m_pTri) + m_pTri->SnapToNearestPeak(m_pTri->GetNodeGq(), m_pTri->GetNodeKfQ()); +} + + +#ifdef USE_GIL + +#include "tlibs/gfx/gil.h" +namespace gil = boost::gil; + +bool ScatteringTriangleScene::ExportBZAccurate(const char* pcFile) const +{ + if(!m_pTri) return false; + + const int iW = 720; + const int iH = 720; + + gil::rgb8_view_t view; + std::vector vecPix; + tl::create_imgview(iW, iH, vecPix, view); + + const int iMaxPeaks = m_pTri->GetMaxPeaks(); + int iXMid = sceneRect().left() + (sceneRect().right()-sceneRect().left())/2; + int iYMid = sceneRect().top() + (sceneRect().bottom()-sceneRect().top())/2; + + int _iY=0; + for(int iY=iYMid-iH/2; iYGetHKLFromPlanePos(dX, -dY); + if(vecHKL.size()!=3) return false; + vecHKL /= m_pTri->GetScaleFactor(); + + const std::vector* pvecNearest = nullptr; + const tl::Kd& kd = m_pTri->GetKdLattice(); + t_vec vecHKLinvA = m_pTri->GetRecipLattice().GetPos(vecHKL[0], vecHKL[1], vecHKL[2]); + + if(kd.GetRootNode()) + { + std::vector stdvecHKL{vecHKLinvA[0], vecHKLinvA[1], vecHKLinvA[2]}; + pvecNearest = &kd.GetNearestNode(stdvecHKL); + } + + if(!pvecNearest) return false; + t_real dDist = ublas::norm_2(tl::make_vec({(*pvecNearest)[0], (*pvecNearest)[1], (*pvecNearest)[2]}) - vecHKLinvA); + + bool bIsDirectBeam = 0; + if(tl::float_equal((*pvecNearest)[3], 0.) && tl::float_equal((*pvecNearest)[4], 0.) && tl::float_equal((*pvecNearest)[5], 0.)) + bIsDirectBeam = 1; + + int iR = ((*pvecNearest)[3]+iMaxPeaks) * 255 / (iMaxPeaks*2); + int iG = ((*pvecNearest)[4]+iMaxPeaks) * 255 / (iMaxPeaks*2); + int iB = ((*pvecNearest)[5]+iMaxPeaks) * 255 / (iMaxPeaks*2); + t_real dBraggAmp = tl::gauss_model(dDist, 0., 0.01, 255., 0.); + iR += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + iG += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + iB += bIsDirectBeam ? -(unsigned int)dBraggAmp : (unsigned int)dBraggAmp; + + iR = tl::clamp(iR, 0, 255); + iG = tl::clamp(iG, 0, 255); + iB = tl::clamp(iB, 0, 255); + + /*view(_iX, _iY) =*/ iterRow[_iX] = gil::rgb8_pixel_t((unsigned char)iR, (unsigned char)iG, (unsigned char)iB); + } + + //tl::log_info("BZ export: Line ", _iY+1, " of ", iH); + } + + if(!tl::save_view(pcFile, &view)) + { + tl::log_err("Cannot write image \"", pcFile, "\"."); + return false; + } + + return true; +} + +#else +bool ScatteringTriangleScene::ExportBZAccurate(const char* pcFile) const { return 0; } +#endif + + +void ScatteringTriangleScene::drawBackground(QPainter* pPainter, const QRectF& rect) +{ + QGraphicsScene::drawBackground(pPainter, rect); + + // TODO: draw accurate BZ +} + +void ScatteringTriangleScene::mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) +{ + bool bHandled = 0; + bool bAllowed = 1; + + // tooltip + if(m_pTri) + { + const t_real dX = pEvt->scenePos().x()/m_pTri->GetScaleFactor(); + const t_real dY = -pEvt->scenePos().y()/m_pTri->GetScaleFactor(); + + t_vec vecHKL = m_pTri->GetHKLFromPlanePos(dX, dY); + tl::set_eps_0(vecHKL, g_dEps); + + if(vecHKL.size()==3) + { + //std::ostringstream ostrPos; + //ostrPos << "(" << vecHKL[0] << ", " << vecHKL[1] << ", " << vecHKL[2] << ")"; + //QToolTip::showText(pEvt->screenPos(), ostrPos.str().c_str()); + + const std::vector* pvecNearest = nullptr; + + const tl::Kd& kd = m_pTri->GetKdLattice(); + const tl::Lattice& recip = m_pTri->GetRecipLattice(); + t_vec vecHKLinvA = recip.GetPos(vecHKL[0], vecHKL[1], vecHKL[2]); + + if(kd.GetRootNode()) + { + std::vector stdvecHKL{vecHKLinvA[0], vecHKLinvA[1], vecHKLinvA[2]}; + pvecNearest = &kd.GetNearestNode(stdvecHKL); + if(pvecNearest->size() < 6) + { + pvecNearest = nullptr; + tl::log_warn("Invalid BZ node."); + } + } + + emit coordsChanged(vecHKL[0], vecHKL[1], vecHKL[2], + pvecNearest != nullptr, + pvecNearest?(*pvecNearest)[3]:0., + pvecNearest?(*pvecNearest)[4]:0., + pvecNearest?(*pvecNearest)[5]:0.); + } + } + + // node dragging + if(m_bMousePressed) + { + QGraphicsItem* pCurItem = mouseGrabberItem(); + if(pCurItem) + { + const int iNodeType = pCurItem->data(TRIANGLE_NODE_TYPE_KEY).toInt(); + + if(m_bSnap || (m_bSnapq && iNodeType == NODE_q)) + { + QList nodes = items(); + std::tuple tupNearest = + get_nearest_node(pEvt->scenePos(), pCurItem, nodes, + m_pTri->GetScaleFactor(), &m_pTri->GetPowder()); + + if(std::get<0>(tupNearest)) + { + pCurItem->setPos(std::get<2>(tupNearest)); + bHandled = 1; + } + } + else if(iNodeType == NODE_KIKF && m_bSnapKiKfToElastic) + { + std::pair pairNearest = + get_nearest_elastic_kikf_pos(pEvt->scenePos() /*m_pTri->GetNodeKiKf()->scenePos()*/, + m_pTri->GetNodeKiQ()->scenePos(), + m_pTri->GetNodeKfQ()->scenePos()); + + if(pairNearest.first) + { + pCurItem->setPos(pairNearest.second); + bHandled = 1; + } + } + + // TODO: case for both snapping and abs ki kf fixed + else if(iNodeType == NODE_Q && m_bKeepAbsKiKf) + { + t_real dX = pEvt->scenePos().x()-pEvt->lastScenePos().x(); + t_real dY = pEvt->scenePos().y()-pEvt->lastScenePos().y(); + + bAllowed = m_pTri->KeepAbsKiKf(dX, dY); + } + } + } + + if(!bHandled && bAllowed) + QGraphicsScene::mouseMoveEvent(pEvt); +} + +void ScatteringTriangleScene::keyPressEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 1; + if(pEvt->key() == Qt::Key_Shift) + m_bSnapKiKfToElastic = 1; + + QGraphicsScene::keyPressEvent(pEvt); +} + +void ScatteringTriangleScene::keyReleaseEvent(QKeyEvent *pEvt) +{ + if(pEvt->key() == Qt::Key_Control) + m_bSnap = 0; + if(pEvt->key() == Qt::Key_Shift) + m_bSnapKiKfToElastic = 0; + + QGraphicsScene::keyReleaseEvent(pEvt); +} + + +// -------------------------------------------------------------------------------- + + +ScatteringTriangleView::ScatteringTriangleView(QWidget* pParent) + : QGraphicsView(pParent) +{ + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + setDragMode(QGraphicsView::ScrollHandDrag); + setMouseTracking(1); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); +} + +ScatteringTriangleView::~ScatteringTriangleView() +{} + +void ScatteringTriangleView::wheelEvent(QWheelEvent *pEvt) +{ +#if QT_VER>=5 + const t_real dDelta = pEvt->angleDelta().y()/8. / 150.; +#else + const t_real dDelta = pEvt->delta()/8. / 150.; +#endif + + const t_real dScale = std::pow(2., dDelta); + this->scale(dScale, dScale); + m_dTotalScale *= dScale; + emit scaleChanged(m_dTotalScale); +} + + +#include "scattering_triangle.moc" diff --git a/tools/taz/scattering_triangle.h b/tools/taz/scattering_triangle.h new file mode 100644 index 0000000..68aa66a --- /dev/null +++ b/tools/taz/scattering_triangle.h @@ -0,0 +1,313 @@ +/** + * Scattering Triangle + * @author tweber + * @date 2014 - 2016 + * @license GPLv2 + */ + +#ifndef __TAZ_SCATT_TRIAG_H__ +#define __TAZ_SCATT_TRIAG_H__ + +#include +#include +#include +#include +#include +#include +#if QT_VER>=5 + #include +#endif + +#include "tlibs/math/linalg.h" +#include "tlibs/math/lattice.h" +#include "tlibs/math/powder.h" +#include "tlibs/math/bz.h" +#include "tlibs/math/neutrons.h" +#include "tlibs/math/kd.h" + +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/formfactors/formfact.h" +#include "libs/spacegroups/latticehelper.h" + +#include "tasoptions.h" +#include "dialogs/RecipParamDlg.h" // for RecipParams struct +#include "dialogs/AtomsDlg.h" + + +#define TRIANGLE_NODE_TYPE_KEY 0 + +enum ScatteringTriangleNodeType +{ + NODE_Q, + NODE_q, + + NODE_BRAGG, + NODE_KIQ, + NODE_KIKF, + + NODE_OTHER +}; + +enum EwaldSphere : int +{ + EWALD_NONE, + EWALD_KI, + EWALD_KF +}; + +class ScatteringTriangle; +class ScatteringTriangleNode : public QGraphicsItem +{ + protected: + ScatteringTriangle *m_pParentItem; + + protected: + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &val) override; + + public: + ScatteringTriangleNode(ScatteringTriangle* pSupItem); +}; + +class RecipPeak : public QGraphicsItem +{ + protected: + QColor m_color = Qt::red; + QString m_strLabel; + //const Brillouin2D* m_pBZ = 0; + t_real_glob m_dRadius = 3.; + + protected: + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + public: + RecipPeak(); + + void SetLabel(const QString& str) { m_strLabel = str; } + void SetColor(const QColor& col) { m_color = col; } + + void SetRadius(t_real_glob dRad) { m_dRadius = dRad; } + t_real_glob GetRadius() const { return m_dRadius; } + //void SetBZ(const Brillouin2D* pBZ) { this->m_pBZ = pBZ; } +}; + +class ScatteringTriangleScene; +class ScatteringTriangle : public QGraphicsItem +{ + protected: + bool m_bReady = 0; + + ScatteringTriangleScene &m_scene; + + ScatteringTriangleNode *m_pNodeKiQ = 0; + ScatteringTriangleNode *m_pNodeKiKf = 0; + ScatteringTriangleNode *m_pNodeKfQ = 0; + ScatteringTriangleNode *m_pNodeGq = 0; + + t_real_glob m_dScaleFactor = 150.; // pixels per A^-1 for zoom == 1. + t_real_glob m_dZoom = 1.; + t_real_glob m_dPlaneDistTolerance = 0.01; + int m_iMaxPeaks = 7; + + tl::Lattice m_lattice, m_recip; + ublas::matrix m_matPlane, m_matPlane_inv; + std::vector m_vecPeaks; + + tl::Powder m_powder; + tl::Kd m_kdLattice; + + bool m_bShowBZ = 1; + tl::Brillouin2D m_bz; + + //tl::Lattice m_recip_unrot; + //t_real_glob m_dAngleRot = 0.; + + bool m_bqVisible = 0; + bool m_bShowEwaldSphere = 1; + bool m_bEwaldAroundKi = 0; + + protected: + virtual QRectF boundingRect() const override; + + public: + ScatteringTriangle(ScatteringTriangleScene& scene); + virtual ~ScatteringTriangle(); + + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget *) override; + + void SetReady(bool bReady) { m_bReady = bReady; } + void nodeMoved(const ScatteringTriangleNode* pNode=0); + + const ublas::matrix& GetPlane() const { return m_matPlane; } + + bool IsReady() const { return m_bReady; } + t_real_glob GetTheta(bool bPosSense) const; + t_real_glob GetTwoTheta(bool bPosSense) const; + t_real_glob GetMonoTwoTheta(t_real_glob dMonoD, bool bPosSense) const; + t_real_glob GetAnaTwoTheta(t_real_glob dAnaD, bool bPosSense) const; + + t_real_glob GetKi() const; + t_real_glob GetKf() const; + t_real_glob GetE() const; + t_real_glob GetQ() const; + t_real_glob Getq() const; + + t_real_glob GetAngleKiQ(bool bSense) const; + t_real_glob GetAngleKfQ(bool bSense) const; + t_real_glob GetAngleQVec0() const; + + void SetTwoTheta(t_real_glob dTT); + void SetAnaTwoTheta(t_real_glob dTT, t_real_glob dAnaD); + void SetMonoTwoTheta(t_real_glob dTT, t_real_glob dMonoD); + + public: + bool HasPeaks() const { return m_vecPeaks.size()!=0 && m_recip.IsInited(); } + void ClearPeaks(); + void CalcPeaks(const LatticeCommon& recipcommon, bool bIsPowder=0); + + void SetPlaneDistTolerance(t_real_glob dTol) { m_dPlaneDistTolerance = dTol; } + void SetMaxPeaks(int iMax) { m_iMaxPeaks = iMax; } + unsigned int GetMaxPeaks() const { return m_iMaxPeaks; } + void SetZoom(t_real_glob dZoom); + t_real_glob GetZoom() const { return m_dZoom; } + + void SetqVisible(bool bVisible); + void SetBZVisible(bool bVisible); + void SetEwaldSphereVisible(EwaldSphere iEw); + + const tl::Powder& GetPowder() const { return m_powder; } + const tl::Kd& GetKdLattice() const { return m_kdLattice; } + + public: + std::vector GetNodes(); + std::vector GetNodeNames() const; + + t_real_glob GetScaleFactor() const { return m_dScaleFactor; } + void SetScaleFactor(t_real_glob dScale) { m_dScaleFactor = dScale; } + + ScatteringTriangleNode* GetNodeGq() { return m_pNodeGq; } + ScatteringTriangleNode* GetNodeKiQ() { return m_pNodeKiQ; } + ScatteringTriangleNode* GetNodeKfQ() { return m_pNodeKfQ; } + ScatteringTriangleNode* GetNodeKiKf() { return m_pNodeKiKf; } + + ublas::vector GetHKLFromPlanePos(t_real_glob x, t_real_glob y) const; + ublas::vector GetQVec(bool bSmallQ=0, bool bRLU=1) const; // careful: check sign + + ublas::vector GetQVecPlane(bool bSmallQ=0) const; + ublas::vector GetKiVecPlane() const; + ublas::vector GetKfVecPlane() const; + + void RotateKiVec0To(bool bSense, t_real_glob dAngle); + void SnapToNearestPeak(ScatteringTriangleNode* pNode, + const ScatteringTriangleNode* pNodeOrg=0); + bool KeepAbsKiKf(t_real_glob dQx, t_real_glob dQy); + + const tl::Lattice& GetRecipLattice() const { return m_recip; } + QPointF GetGfxMid() const; + + void AllowMouseMove(bool bAllow); +}; + + +class ScatteringTriangleScene : public QGraphicsScene +{ Q_OBJECT + protected: + ScatteringTriangle *m_pTri; + t_real_glob m_dMonoD = 3.355; + t_real_glob m_dAnaD = 3.355; + + bool m_bSamplePosSense = 1; + bool m_bAnaPosSense = 0; + bool m_bMonoPosSense = 0; + + bool m_bDontEmitChange = 0; + bool m_bSnap = 0; + bool m_bSnapq = 1; + bool m_bMousePressed = 0; + + bool m_bKeepAbsKiKf = 1; + bool m_bSnapKiKfToElastic = 0; + + public: + ScatteringTriangleScene(QObject *pParent=nullptr); + virtual ~ScatteringTriangleScene(); + + void SetEmitChanges(bool bEmit) { m_bDontEmitChange = !bEmit; } + // emits triangleChanged + void emitUpdate(); + // emits paramsChanged + void emitAllParams(); + void SetDs(t_real_glob dMonoD, t_real_glob dAnaD); + + void SetSampleSense(bool bPos); + void SetMonoSense(bool bPos); + void SetAnaSense(bool bPos); + + const ScatteringTriangle* GetTriangle() const { return m_pTri; } + ScatteringTriangle* GetTriangle() { return m_pTri; } + + void CheckForSpurions(); + + bool ExportBZAccurate(const char* pcFile) const; + + public slots: + void tasChanged(const TriangleOptions& opts); + void scaleChanged(t_real_glob dTotalScale); + + void setSnapq(bool bSnap); + bool getSnapq() const { return m_bSnapq; } + + void setKeepAbsKiKf(bool bKeep) { m_bKeepAbsKiKf = bKeep; } + bool getKeepAbsKiKf() const { return m_bKeepAbsKiKf; } + + signals: + // relevant parameters for instrument view + void triangleChanged(const TriangleOptions& opts); + // all parameters + void paramsChanged(const RecipParams& parms); + + void spurionInfo(const tl::ElasticSpurion& spuris, + const std::vector>& vecInelCKI, + const std::vector>& vecInelCKF); + + void coordsChanged(t_real_glob dh, t_real_glob dk, t_real_glob dl, + bool bHasNearest, + t_real_glob dNearestH, t_real_glob dNearestK, t_real_glob dNearestL); + + void nodeEvent(bool bStarted); + + protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *pEvt) override; + + virtual void keyPressEvent(QKeyEvent *pEvt) override; + virtual void keyReleaseEvent(QKeyEvent *pEvt) override; + + virtual void drawBackground(QPainter*, const QRectF&) override; +}; + + +class ScatteringTriangleView : public QGraphicsView +{ + Q_OBJECT + protected: + t_real_glob m_dTotalScale = 1.; + virtual void wheelEvent(QWheelEvent* pEvt) override; + + public: + ScatteringTriangleView(QWidget* pParent = 0); + virtual ~ScatteringTriangleView(); + + signals: + void scaleChanged(t_real_glob dTotalScale); +}; + +#endif diff --git a/tools/taz/sics.cpp b/tools/taz/sics.cpp new file mode 100644 index 0000000..9675256 --- /dev/null +++ b/tools/taz/sics.cpp @@ -0,0 +1,238 @@ +/* + * Connection to Sics + * @author tweber + * @date 26-aug-2015 + * @license GPLv2 + */ + +#include "sics.h" +#include "tlibs/string/string.h" +#include "tlibs/log/log.h" +#include "tlibs/helper/misc.h" +#include "tlibs/time/chrono.h" +#include "libs/globals.h" +#include + +using t_real = t_real_glob; + + +SicsCache::SicsCache(QSettings* pSettings) : m_pSettings(pSettings) +{ + m_tcp.add_connect(boost::bind(&SicsCache::slot_connected, this, _1, _2)); + m_tcp.add_disconnect(boost::bind(&SicsCache::slot_disconnected, this, _1, _2)); + m_tcp.add_receiver(boost::bind(&SicsCache::slot_receive, this, _1)); +} + +SicsCache::~SicsCache() +{ + disconnect(); +} + +void SicsCache::connect(const std::string& strHost, const std::string& strPort, + const std::string& strUser, const std::string& strPass) +{ + if(m_pSettings && m_pSettings->contains("net/poll")) + m_iPollRate = m_pSettings->value("net/poll").value(); + + m_mapCache.clear(); + emit cleared_cache(); + + m_strUser = strUser; + m_strPass = strPass; + + if(!m_tcp.connect(strHost, strPort)) + return; +} + +void SicsCache::disconnect() +{ + m_bPollerActive.store(false); + if(m_pthPoller && m_pthPoller->joinable()) + m_pthPoller->join(); + if(m_pthPoller) + { + delete m_pthPoller; + m_pthPoller = nullptr; + } + + m_tcp.disconnect(); +} + +void SicsCache::refresh() +{} + +void SicsCache::start_poller() +{ + m_bPollerActive.store(true); + + m_pthPoller = new std::thread([this]() + { + if(m_strUser.size() || m_strPass.size()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + m_tcp.write(m_strUser + " " + m_strPass + "\n"); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + + while(m_bPollerActive.load()) + { + std::string strMsg; + strMsg += "DM\nDA\n"; + strMsg += "AS\nBS\nCS\nAA\nBB\nCC\n"; + strMsg += "AX\nAY\nAZ\nBX\nBY\nBZ\n"; + strMsg += "A2\nA3\nA4\nA6\n"; + + m_tcp.write(strMsg); + std::this_thread::sleep_for(std::chrono::milliseconds(m_iPollRate)); + } + }); +} + +void SicsCache::slot_connected(const std::string& strHost, const std::string& strSrv) +{ + tl::log_info("Connected to ", strHost, " on port ", strSrv, "."); + start_poller(); + + QString qstrHost = strHost.c_str(); + QString qstrSrv = strSrv.c_str(); + emit connected(qstrHost, qstrSrv); +} + +void SicsCache::slot_disconnected(const std::string& strHost, const std::string& strSrv) +{ + tl::log_info("Disconnected from ", strHost, " on port ", strSrv, "."); + m_bPollerActive.store(false); + emit disconnected(); +} + +void SicsCache::slot_receive(const std::string& str) +{ +#ifndef NDEBUG + tl::log_debug("Received: ", str); +#endif + if(str=="OK" || str=="Login OK") + return; + + if(str.substr(0, 5) == "ERROR") + { + tl::log_err("Sics replied with: ", str); + tl::log_err("Stopping poller..."); + m_bPollerActive.store(false); + //this->disconnect(); + return; + } + + std::pair pairKeyVal = tl::split_first(str, "=", 1); + if(pairKeyVal.second == "") + { + tl::log_err("Invalid net reply: \"", str, "\""); + return; + } + + + const std::string& strKey = pairKeyVal.first; + const std::string& strVal = pairKeyVal.second; + + if(strVal.length() == 0) + return; + + CacheVal cacheval; + cacheval.strVal = strVal; + boost::to_upper(cacheval.strVal); + cacheval.dTimestamp = tl::epoch(); + m_mapCache[strKey] = cacheval; + + //std::cout << strKey << " = " << strVal << std::endl; + emit updated_cache_value(strKey, cacheval); + + + CrystalOptions crys; + TriangleOptions triag; + + // monochromator + if(tl::str_is_equal(strKey, "A2", false)) + { + triag.bChangedMonoTwoTheta = 1; + triag.dMonoTwoTheta = tl::d2r(tl::str_to_var(strVal)); + } + // analyser + else if(tl::str_is_equal(strKey, "A6", false)) + { + triag.bChangedAnaTwoTheta = 1; + triag.dAnaTwoTheta = tl::d2r(tl::str_to_var(strVal)); + } + // sample + else if(tl::str_is_equal(strKey, "A4", false)) + { + triag.bChangedTwoTheta = 1; + triag.dTwoTheta = tl::d2r(tl::str_to_var(strVal)); + } + else if(tl::str_is_equal(strKey, "A3", false)) + { + triag.bChangedAngleKiVec0 = 1; + triag.dAngleKiVec0 = -tl::d2r(tl::str_to_var(strVal)); + } + // lattice constants and angles + else if(tl::str_is_equal_to_either(strKey, {"AS", "BS", "CS", "AA", "BB", "CC"}, false)) + { + decltype(m_mapCache)::const_iterator iterAS = m_mapCache.find("AS"); + decltype(m_mapCache)::const_iterator iterBS = m_mapCache.find("BS"); + decltype(m_mapCache)::const_iterator iterCS = m_mapCache.find("CS"); + decltype(m_mapCache)::const_iterator iterAA = m_mapCache.find("AA"); + decltype(m_mapCache)::const_iterator iterBB = m_mapCache.find("BB"); + decltype(m_mapCache)::const_iterator iterCC = m_mapCache.find("CC"); + + if(iterAS==m_mapCache.end() || iterBS==m_mapCache.end() || iterCS==m_mapCache.end() + || iterAA==m_mapCache.end() || iterBB==m_mapCache.end() || iterCC==m_mapCache.end()) + return; + + crys.bChangedLattice = crys.bChangedLatticeAngles = 1; + crys.dLattice[0] = tl::str_to_var(iterAS->second.strVal); + crys.dLattice[1] = tl::str_to_var(iterBS->second.strVal); + crys.dLattice[2] = tl::str_to_var(iterCS->second.strVal); + crys.dLatticeAngles[0] = tl::str_to_var(iterAA->second.strVal); + crys.dLatticeAngles[1] = tl::str_to_var(iterBB->second.strVal); + crys.dLatticeAngles[2] = tl::str_to_var(iterCC->second.strVal); + } + // orientation reflexes + else if(tl::str_is_equal_to_either(strKey, {"AX", "AY", "AZ", "BX", "BY", "BZ"}, false)) + { + decltype(m_mapCache)::const_iterator iterAX = m_mapCache.find("AX"); + decltype(m_mapCache)::const_iterator iterAY = m_mapCache.find("AY"); + decltype(m_mapCache)::const_iterator iterAZ = m_mapCache.find("AZ"); + decltype(m_mapCache)::const_iterator iterBX = m_mapCache.find("BX"); + decltype(m_mapCache)::const_iterator iterBY = m_mapCache.find("BY"); + decltype(m_mapCache)::const_iterator iterBZ = m_mapCache.find("BZ"); + + if(iterAX==m_mapCache.end() || iterAY==m_mapCache.end() || iterAZ==m_mapCache.end() + || iterBX==m_mapCache.end() || iterBY==m_mapCache.end() || iterBZ==m_mapCache.end()) + return; + + crys.bChangedPlane1 = crys.bChangedPlane2 = 1; + crys.dPlane1[0] = tl::str_to_var(iterAX->second.strVal); + crys.dPlane1[1] = tl::str_to_var(iterAY->second.strVal); + crys.dPlane1[2] = tl::str_to_var(iterAZ->second.strVal); + crys.dPlane2[0] = tl::str_to_var(iterBX->second.strVal); + crys.dPlane2[1] = tl::str_to_var(iterBY->second.strVal); + crys.dPlane2[2] = tl::str_to_var(iterBZ->second.strVal); + } + else if(tl::str_is_equal(strKey, "DM", false)) + { + triag.dMonoD = tl::str_to_var(strVal); + triag.bChangedMonoD = 1; + } + else if(tl::str_is_equal(strKey, "DA", false)) + { + triag.dAnaD = tl::str_to_var(strVal); + triag.bChangedAnaD = 1; + } + + // need to make crys & triag member variables and protected by a mutex + // for the following: + //if(tl::has_map_all_keys(m_mapCache, + // {"A2", "A6", "A4", "A3", "AS", "BS", "CS", "AA", "BB", "CC", + // "AX", "AY", "AZ", "BX", "BY", "BZ", "DM", "DA"})) + emit vars_changed(crys, triag); +} + +#include "sics.moc" diff --git a/tools/taz/sics.h b/tools/taz/sics.h new file mode 100644 index 0000000..e147a4d --- /dev/null +++ b/tools/taz/sics.h @@ -0,0 +1,54 @@ +/* + * Connection to Sics + * @author tweber + * @date 26-aug-2015 + * @license GPLv2 + */ + +#ifndef __SICS_CONN_H__ +#define __SICS_CONN_H__ + +#include "net.h" +#include "tlibs/net/tcp.h" + +#include +#include +#include +#include +#include + + +class SicsCache : public NetCache +{ Q_OBJECT + protected: + QSettings* m_pSettings = 0; + + tl::TcpTxtClient<> m_tcp; + t_mapCacheVal m_mapCache; + + std::string m_strUser, m_strPass; + + std::atomic m_bPollerActive; + std::thread *m_pthPoller = nullptr; + + unsigned int m_iPollRate = 750; + + protected: + // endpoints of the TcpClient signals + void slot_connected(const std::string& strHost, const std::string& strSrv); + void slot_disconnected(const std::string& strHost, const std::string& strSrv); + void slot_receive(const std::string& str); + + void start_poller(); + + public: + SicsCache(QSettings* pSettings=0); + virtual ~SicsCache(); + + virtual void connect(const std::string& strHost, const std::string& strPort, + const std::string& strUser, const std::string& strPass) override; + virtual void disconnect() override; + virtual void refresh() override; +}; + +#endif diff --git a/tools/taz/tas_layout.cpp b/tools/taz/tas_layout.cpp new file mode 100644 index 0000000..f4ca74a --- /dev/null +++ b/tools/taz/tas_layout.cpp @@ -0,0 +1,712 @@ +/* + * TAS layout + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#include "tas_layout.h" +#include "tlibs/string/spec_char.h" +#include + +using t_real = t_real_glob; +using t_vec = ublas::vector; +using t_mat = ublas::matrix; + + +static inline bool flip_text(t_real _dAngle) +{ + t_real dAngle = std::fmod(_dAngle, 360.); + return std::abs(dAngle) > 90. && std::abs(dAngle) < 270.; +} + + +TasLayoutNode::TasLayoutNode(TasLayout* pSupItem) : m_pParentItem(pSupItem) +{ + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setCursor(Qt::CrossCursor); +} + +QRectF TasLayoutNode::boundingRect() const +{ + return QRectF(-5., -5., 10., 10.); +} + +void TasLayoutNode::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->drawEllipse(QRectF(-2., -2., 4., 4.)); +} + +QVariant TasLayoutNode::itemChange(GraphicsItemChange change, const QVariant &val) +{ + //std::cout << change << std::endl; + QVariant var = QGraphicsItem::itemChange(change, val); + + if(change == QGraphicsItem::ItemPositionHasChanged) + m_pParentItem->nodeMoved(this); + + return var; +} + +// -------------------------------------------------------------------------------- + +TasLayout::TasLayout(TasLayoutScene& scene) : m_scene(scene) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + + m_pSrc = new TasLayoutNode(this); + m_pMono = new TasLayoutNode(this); + m_pSample = new TasLayoutNode(this); + m_pAna = new TasLayoutNode(this); + m_pDet = new TasLayoutNode(this); + + m_pSrc->setToolTip("Source"); + m_pMono->setToolTip("Monochromator"); + m_pSample->setToolTip("Sample"); + m_pAna->setToolTip("Analyser"); + m_pDet->setToolTip("Detector"); + + m_pSrc->setPos(200., m_dLenMonoSample*m_dScaleFactor); + m_pMono->setPos(0., m_dLenMonoSample*m_dScaleFactor); + m_pSample->setPos(0., 0.); + m_pAna->setPos(-m_dLenSampleAna*m_dScaleFactor, 0.); + m_pDet->setPos(-100., -m_dLenAnaDet*m_dScaleFactor); + + AllowMouseMove(1); + + scene.addItem(m_pSrc); + scene.addItem(m_pMono); + scene.addItem(m_pSample); + scene.addItem(m_pAna); + scene.addItem(m_pDet); + + setAcceptedMouseButtons(0); + m_bReady = 1; +} + +TasLayout::~TasLayout() +{ + m_bReady = 0; + + delete m_pSrc; + delete m_pMono; + delete m_pSample; + delete m_pAna; + delete m_pDet; +} + +void TasLayout::AllowMouseMove(bool bAllow) +{ + //m_pSrc->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pMono->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pSample->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pAna->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pDet->setFlag(QGraphicsItem::ItemIsMovable, bAllow); +} + +void TasLayout::nodeMoved(const TasLayoutNode *pNode) +{ + if(!m_bReady) return; + + static bool bAllowUpdate = 1; + if(!bAllowUpdate) return; + + const t_vec vecSrc = qpoint_to_vec(mapFromItem(m_pSrc, 0, 0)); + const t_vec vecMono = qpoint_to_vec(mapFromItem(m_pMono, 0, 0)); + const t_vec vecSample = qpoint_to_vec(mapFromItem(m_pSample, 0, 0)); + const t_vec vecAna = qpoint_to_vec(mapFromItem(m_pAna, 0, 0)); + const t_vec vecDet = qpoint_to_vec(mapFromItem(m_pDet, 0, 0)); + + bAllowUpdate = 0; + if(pNode==m_pSample) + { + //tl::log_debug("Sample node moved."); + + t_real dTwoTheta = m_dTwoTheta; + t_real dAnaTwoTheta = m_dAnaTwoTheta; + + t_vec vecSrcMono = vecMono-vecSrc; + vecSrcMono /= ublas::norm_2(vecSrcMono); + + t_vec vecMonoSample = vecSample-vecMono; + if(m_bAllowChanges) + m_dLenMonoSample = ublas::norm_2(vecMonoSample)/m_dScaleFactor; + vecMonoSample /= ublas::norm_2(vecMonoSample); + + if(m_bAllowChanges) + { + m_dMonoTwoTheta = -(tl::vec_angle(vecMonoSample) - tl::vec_angle(vecSrcMono)); + if(m_dMonoTwoTheta < -tl::get_pi()) m_dMonoTwoTheta += 2.*tl::get_pi(); + if(m_dMonoTwoTheta > tl::get_pi()) m_dMonoTwoTheta -= 2.*tl::get_pi(); + } + + + t_vec vecSampleAna = + ublas::prod(tl::rotation_matrix_2d(-dTwoTheta), vecMonoSample); + vecSampleAna /= ublas::norm_2(vecSampleAna); + vecSampleAna *= m_dLenSampleAna*m_dScaleFactor; + + t_vec vecAnaNew = vecSample + vecSampleAna; + m_pAna->setPos(vec_to_qpoint(vecAnaNew)); + + + + vecSampleAna /= ublas::norm_2(vecSampleAna); + + t_vec vecAnaDet = + ublas::prod(tl::rotation_matrix_2d(-dAnaTwoTheta), vecSampleAna); + vecAnaDet /= ublas::norm_2(vecAnaDet); + vecAnaDet *= m_dLenAnaDet*m_dScaleFactor; + + m_pDet->setPos(vec_to_qpoint(vecAnaNew+vecAnaDet)); + + + TriangleOptions opts; + opts.bChangedMonoTwoTheta = 1; + opts.bChangedTwoTheta = 1; + opts.bChangedAnaTwoTheta = 1; + opts.dMonoTwoTheta = m_dMonoTwoTheta; + opts.dTwoTheta = dTwoTheta; + opts.dAnaTwoTheta = dAnaTwoTheta; + m_scene.emitUpdate(opts); + } + else if(pNode==m_pMono) + { + //tl::log_debug("Mono node moved."); + + t_vec vecSrcMono = vecMono-vecSrc; + vecSrcMono /= ublas::norm_2(vecSrcMono); + + t_vec vecMonoSample = + ublas::prod(tl::rotation_matrix_2d(-m_dMonoTwoTheta), vecSrcMono); + vecMonoSample /= ublas::norm_2(vecMonoSample); + vecMonoSample *= m_dLenMonoSample*m_dScaleFactor; + + t_vec vecSampleNew = vecMono + vecMonoSample; + m_pSample->setPos(vec_to_qpoint(vecSampleNew)); + + + t_vec vecSampleAna = + ublas::prod(tl::rotation_matrix_2d(-m_dTwoTheta), vecMonoSample); + //t_vec vecSampleAna = vecAna - vecSample; + vecSampleAna /= ublas::norm_2(vecSampleAna); + vecSampleAna *= m_dLenSampleAna*m_dScaleFactor; + + t_vec vecAnaNew = vecSampleNew + vecSampleAna; + m_pAna->setPos(vec_to_qpoint(vecAnaNew)); + + + t_vec vecAnaDet = + ublas::prod(tl::rotation_matrix_2d(-m_dAnaTwoTheta), vecSampleAna); + vecAnaDet /= ublas::norm_2(vecAnaDet); + vecAnaDet *= m_dLenAnaDet*m_dScaleFactor; + + m_pDet->setPos(vec_to_qpoint(vecAnaNew + vecAnaDet)); + } + else if(pNode==m_pDet) + { + //tl::log_debug("Det node moved."); + + t_vec vecSampleAna = vecAna - vecSample; + vecSampleAna /= ublas::norm_2(vecSampleAna); + + t_vec vecAnaDet = vecDet-vecAna; + if(m_bAllowChanges) + m_dLenAnaDet = ublas::norm_2(vecAnaDet)/m_dScaleFactor; + vecAnaDet /= ublas::norm_2(vecAnaDet); + + if(m_bAllowChanges) + { + m_dAnaTwoTheta = -(tl::vec_angle(vecAnaDet) - tl::vec_angle(vecSampleAna)); + if(m_dAnaTwoTheta < -tl::get_pi()) m_dAnaTwoTheta += 2.*tl::get_pi(); + if(m_dAnaTwoTheta > tl::get_pi()) m_dAnaTwoTheta -= 2.*tl::get_pi(); + } + + //std::cout << m_dAnaTwoTheta/M_PI*180. << std::endl; + + TriangleOptions opts; + opts.bChangedAnaTwoTheta = 1; + opts.dAnaTwoTheta = m_dAnaTwoTheta; + m_scene.emitUpdate(opts); + } + + if(/*pNode==m_pMono ||*/ pNode==m_pAna) + { + //tl::log_debug("Ana node moved."); + + t_vec vecSampleAna = vecAna-vecSample; + if(pNode==m_pAna && m_bAllowChanges) + m_dLenSampleAna = ublas::norm_2(vecSampleAna)/m_dScaleFactor; + vecSampleAna /= ublas::norm_2(vecSampleAna); + + t_vec vecAnaDet = + ublas::prod(tl::rotation_matrix_2d(-m_dAnaTwoTheta), vecSampleAna); + vecAnaDet /= ublas::norm_2(vecAnaDet); + vecAnaDet *= m_dLenAnaDet*m_dScaleFactor; + + m_pDet->setPos(vec_to_qpoint(vecAna+vecAnaDet)); + + t_vec vecMonoSample = vecSample - vecMono; + vecMonoSample /= ublas::norm_2(vecMonoSample); + + if(m_bAllowChanges) + { + m_dTwoTheta = -(tl::vec_angle(vecSampleAna) - tl::vec_angle(vecMonoSample)); + if(m_dTwoTheta < -tl::get_pi()) m_dTwoTheta += 2.*tl::get_pi(); + if(m_dTwoTheta > tl::get_pi()) m_dTwoTheta -= 2.*tl::get_pi(); + } + + TriangleOptions opts; + opts.bChangedTwoTheta = 1; + opts.dTwoTheta = m_dTwoTheta; + m_scene.emitUpdate(opts); + } + + bAllowUpdate = 1; + this->update(); + m_scene.emitAllParams(); +} + +QRectF TasLayout::boundingRect() const +{ + return QRectF(-1000.*m_dZoom, -1000.*m_dZoom, + 2000.*m_dZoom, 2000.*m_dZoom); +} + +void TasLayout::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + + const bool bDisplayLengths = 0; + + QPointF ptSrc = mapFromItem(m_pSrc, 0, 0) * m_dZoom; + QPointF ptMono = mapFromItem(m_pMono, 0, 0) * m_dZoom; + QPointF ptSample = mapFromItem(m_pSample, 0, 0) * m_dZoom; + QPointF ptAna = mapFromItem(m_pAna, 0, 0) * m_dZoom; + QPointF ptDet = mapFromItem(m_pDet, 0, 0) * m_dZoom; + + QLineF lineSrcMono(ptSrc, ptMono); + QLineF lineKi(ptMono, ptSample); + QLineF lineKf(ptSample, ptAna); + QLineF lineAnaDet(ptAna, ptDet); + + QPen penOrig = painter->pen(); + + painter->drawLine(lineSrcMono); + painter->drawLine(lineKi); + painter->drawLine(lineKf); + painter->drawLine(lineAnaDet); + + + // write lengths + QPointF ptMidKi = ptMono + (ptSample-ptMono)/2.; + QPointF ptMidKf = ptSample + (ptAna-ptSample)/2.; + QPointF ptMidAnaDet = ptAna + (ptDet-ptAna)/2.; + + if(bDisplayLengths) + { + std::ostringstream ostrLenKi, ostrLenKf, ostrLenAnaDet; + ostrLenKi.precision(g_iPrecGfx); + ostrLenKf.precision(g_iPrecGfx); + ostrLenAnaDet.precision(g_iPrecGfx); + + ostrLenKi << m_dLenMonoSample << " cm"; + ostrLenKf << m_dLenSampleAna << " cm"; + ostrLenAnaDet << m_dLenAnaDet << " cm"; + + painter->drawText(ptMidKi, ostrLenKi.str().c_str()); + painter->drawText(ptMidKf, ostrLenKf.str().c_str()); + painter->drawText(ptMidAnaDet, ostrLenAnaDet.str().c_str()); + } + + + + t_vec vecSrc = qpoint_to_vec(ptSrc); + t_vec vecMono = qpoint_to_vec(ptMono); + t_vec vecSample = qpoint_to_vec(ptSample); + t_vec vecAna = qpoint_to_vec(ptAna); + t_vec vecDet = qpoint_to_vec(ptDet); + + t_vec vecSrcMono = vecMono-vecSrc; + t_vec vecMonoSample = vecSample-vecMono; + t_vec vecSampleAna = vecAna-vecSample; + t_vec vecAnaDet = vecDet-vecAna; + + t_real dThetas[] = {-m_dMonoTwoTheta/t_real(2.), -m_dAnaTwoTheta/t_real(2.), -m_dTheta}; + std::vector vecPos = {&vecMono, &vecAna, &vecSample}; + std::vector vecDirs = {&vecSrcMono, &vecSampleAna, &vecMonoSample}; + QColor colThs[] = {Qt::gray, Qt::gray, Qt::red}; + const char* pcComp[] = {"M", "A", "S"}; + + QLineF lineRot[3]; + QPointF ptThP[3]; + + // mono/ana/sample theta rotation + for(std::size_t iTh=0; iThsetPen(pen); + painter->drawLine(lineRot[iTh]); + + + // component names + painter->setPen(penOrig); + painter->save(); + painter->translate(vec_to_qpoint(*vecPos[iTh])); + t_real dCompAngle = 180. + tl::r2d(tl::vec_angle(vecRotDir)); + painter->rotate(dCompAngle); + painter->translate(-4., 16.); + if(flip_text(dCompAngle)) + { + painter->translate(4., -8.); + painter->rotate(180.); + } + painter->drawText(QPointF(0., 0.), pcComp[iTh]); + painter->restore(); + } + + painter->drawText(ptMono - vec_to_qpoint(vecSrcMono*1.1), "R"); + painter->drawText(ptAna + vec_to_qpoint(vecAnaDet*1.1), "D"); + + + // dashed extended lines + painter->setPen(Qt::DashLine); + QLineF lineSrcMono_ext(ptMono, ptMono + (ptMono-ptSrc)/2.); + QLineF lineki_ext(ptSample, ptSample + (ptSample-ptMono)/2.); + QLineF linekf_ext(ptAna, ptAna + (ptAna-ptSample)/2.); + + painter->drawLine(lineSrcMono_ext); + painter->drawLine(lineki_ext); + painter->drawLine(linekf_ext); + + + + QLineF *plineQ = nullptr; + QPointF *pptQ = nullptr; + // Q vector direction visible? + if(this->m_bRealQVisible) + { + //log_info("angle kiQ: ", m_dAngleKiQ/M_PI*180.); + const t_real &dAngleKiQ = m_dAngleKiQ; + t_mat matRotQ = tl::rotation_matrix_2d(dAngleKiQ); + t_vec vecKi = vecSample-vecMono; + t_vec vecQ = ublas::prod(matRotQ, vecKi); + vecQ /= ublas::norm_2(vecQ); + vecQ *= (m_dLenMonoSample + m_dLenSampleAna)/2.; // some arbitrary length + vecQ *= m_dScaleFactor * m_dZoom; + + pptQ = new QPointF(vec_to_qpoint(vecSample + vecQ)); + plineQ = new QLineF(ptSample, *pptQ); + + painter->setPen(Qt::red); + painter->drawLine(*plineQ); + painter->save(); + painter->translate(ptSample); + const t_real dQAngle = -plineQ->angle(); + painter->rotate(dQAngle); + painter->translate(QPointF(plineQ->length()/2.,12.)); + if(flip_text(dQAngle)) + painter->rotate(180.); + painter->drawText(QPointF(0,0), "Q"); + painter->restore(); + } + painter->setPen(penOrig); + + + // angle arcs + const QLineF* pLines1[] = {&lineSrcMono, &lineKi, &lineKf, &lineRot[2]}; + const QLineF* pLines2[] = {&lineKi, &lineKf, &lineAnaDet, &lineKi}; + const QPointF* pPoints[] = {&ptMono, &ptSample, &ptAna, &ptSample}; + const QPointF* pPoints_ext[] = {&ptSrc, &ptMono, &ptSample, &ptThP[2]}; + const t_real dAngles[] = {m_dMonoTwoTheta, m_dTwoTheta, m_dAnaTwoTheta, -m_dTheta}; + const t_real dAngleOffs[] = {0., 0., 0., 180.}; + + QPen pen1(Qt::blue); + QPen pen2(Qt::red); + QPen* arcPens[] = {&pen1, &pen1, &pen1, &pen2}; + + const std::wstring& strDEG = tl::get_spec_char_utf16("deg"); + + for(std::size_t i=0; ilength() + pLines2[i]->length()) / 2. / 3.; + t_real dBeginArcAngle = pLines1[i]->angle() + dAngleOffs[i]; + t_real dArcAngle = tl::r2d(dAngles[i]); + + painter->setPen(*arcPens[i]); + painter->drawArc(QRectF(pPoints[i]->x()-dArcSize/2., pPoints[i]->y()-dArcSize/2., + dArcSize, dArcSize), dBeginArcAngle*16., dArcAngle*16.); + + + std::wostringstream ostrAngle; + ostrAngle.precision(g_iPrecGfx); + if(!tl::is_nan_or_inf(dArcAngle)) + ostrAngle << std::fabs(dArcAngle) << strDEG; + else + ostrAngle << "invalid"; + + + bool bFlip = dAngleOffs[i] > 90.; + t_real dTotalAngle = -dBeginArcAngle-dArcAngle*0.5 + 180.; + if(bFlip) dTotalAngle += 180.; + t_real dTransScale = bFlip ? -40. : 80.; + dTransScale *= m_dZoom; + painter->save(); + painter->translate(*pPoints[i]); + painter->rotate(dTotalAngle); + painter->translate(-dTransScale, +4.); + if(flip_text(dTotalAngle)) + { + if(bFlip) + painter->translate(-dTransScale, -8.); + else + painter->translate(dTransScale*0.5, -8.); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrAngle.str().c_str())); + painter->restore(); + } + + painter->setPen(penOrig); + + + // arrow heads + const QLineF* pLines_arrow[] = {&lineKi, &lineKf, plineQ, &lineSrcMono, &lineAnaDet}; + const QPointF* pPoints_arrow[] = {&ptSample, &ptAna, pptQ, &ptMono, &ptDet}; + QColor colArrowHead[] = {Qt::black, Qt::black, Qt::red, Qt::gray, Qt::gray}; + for(std::size_t i=0; iangle() - 90.); + t_real dC = std::cos(dAng); + t_real dS = std::sin(dAng); + + t_real dTriagX = 5., dTriagY = 10.; + QPointF ptTriag1 = *pPoints_arrow[i] + QPointF(dTriagX*dC + dTriagY*dS, -dTriagX*dS + dTriagY*dC); + QPointF ptTriag2 = *pPoints_arrow[i] + QPointF(-dTriagX*dC + dTriagY*dS, dTriagX*dS + dTriagY*dC); + + QPainterPath triag; + triag.moveTo(*pPoints_arrow[i]); + triag.lineTo(ptTriag1); + triag.lineTo(ptTriag2); + + painter->setPen(colArrowHead[i]); + painter->fillPath(triag, colArrowHead[i]); + } + + painter->setPen(penOrig); + + if(plineQ) delete plineQ; + if(pptQ) delete pptQ; +} + + +void TasLayout::SetSampleTwoTheta(t_real dAngle) +{ + m_dTwoTheta = dAngle; + //std::cout << m_dTwoTheta/M_PI*180. << std::endl; + + t_vec vecMono = qpoint_to_vec(mapFromItem(m_pMono, 0, 0)); + t_vec vecSample = qpoint_to_vec(mapFromItem(m_pSample, 0, 0)); + t_vec vecAna = qpoint_to_vec(mapFromItem(m_pAna, 0, 0)); + + t_vec vecKi = vecSample - vecMono; + vecKi /= ublas::norm_2(vecKi); + t_real dLenKf = ublas::norm_2(vecAna-vecSample); + + //std::cout << dAngle/M_PI*180. << std::endl; + t_vec vecKf = ublas::prod(tl::rotation_matrix_2d(-dAngle), vecKi); + vecKf /= ublas::norm_2(vecKf); + vecKf *= dLenKf; + + m_pAna->setPos(vec_to_qpoint(vecSample + vecKf)); + + nodeMoved(m_pSample); + nodeMoved(m_pAna); +} + +void TasLayout::SetSampleTheta(t_real dAngle) +{ + m_dTheta = dAngle; + nodeMoved(); +} + +void TasLayout::SetMonoTwoTheta(t_real dAngle) +{ + m_dMonoTwoTheta = dAngle; + nodeMoved(m_pMono); +} + +void TasLayout::SetAnaTwoTheta(t_real dAngle) +{ + m_dAnaTwoTheta = dAngle; + nodeMoved(m_pAna); +} + +void TasLayout::SetAngleKiQ(t_real dAngle) +{ + m_dAngleKiQ = dAngle; + nodeMoved(); +} + +void TasLayout::SetRealQVisible(bool bVisible) +{ + m_bRealQVisible = bVisible; + this->update(); +} + +void TasLayout::SetZoom(t_real dZoom) +{ + m_dZoom = dZoom; + m_scene.update(); +} + +std::vector TasLayout::GetNodes() +{ + return std::vector + { m_pSrc, m_pMono, m_pSample, m_pAna, m_pDet }; +} + +std::vector TasLayout::GetNodeNames() const +{ + return std::vector + { "source", "monochromator", "sample", "analyser", "detector" }; +} + +// -------------------------------------------------------------------------------- + + +TasLayoutScene::TasLayoutScene(QObject *pParent) : QGraphicsScene(pParent) +{ + m_pTas = new TasLayout(*this); + this->addItem(m_pTas); +} + +TasLayoutScene::~TasLayoutScene() +{ + delete m_pTas; +} + +void TasLayoutScene::emitAllParams() +{ + if(!m_pTas || !m_pTas->IsReady() || m_bDontEmitChange) + return; + + RealParams parms; + parms.dAnaTT = m_pTas->GetAnaTwoTheta(); + parms.dAnaT = m_pTas->GetAnaTheta(); + parms.dMonoTT = m_pTas->GetMonoTwoTheta(); + parms.dMonoT = m_pTas->GetMonoTheta(); + parms.dSampleTT = m_pTas->GetSampleTwoTheta(); + parms.dSampleT = m_pTas->GetSampleTheta(); + + parms.dLenMonoSample = m_pTas->GetLenMonoSample(); + parms.dLenSampleAna = m_pTas->GetLenSampleAna(); + parms.dLenAnaDet = m_pTas->GetLenAnaDet(); + + //log_info(parms.dSampleT/M_PI*180.); + //log_debug("tas: emitAllParams"); + emit paramsChanged(parms); +} + +void TasLayoutScene::triangleChanged(const TriangleOptions& opts) +{ + if(!m_pTas || !m_pTas->IsReady()) + return; + + //tl::log_debug("triangle changed"); + m_bDontEmitChange = 1; + m_pTas->AllowChanges(0); + + if(opts.bChangedMonoTwoTheta) + m_pTas->SetMonoTwoTheta(opts.dMonoTwoTheta); + if(opts.bChangedAnaTwoTheta) + m_pTas->SetAnaTwoTheta(opts.dAnaTwoTheta); + if(opts.bChangedTheta) + m_pTas->SetSampleTheta(opts.dTheta); + if(opts.bChangedTwoTheta) + m_pTas->SetSampleTwoTheta(opts.dTwoTheta); + + //if(opts.bChangedAngleKiQ) + // m_pTas->SetAngleKiQ(opts.dAngleKiQ); + + m_pTas->AllowChanges(1); + m_bDontEmitChange = 0; +} + +void TasLayoutScene::recipParamsChanged(const RecipParams& params) +{ + m_pTas->SetAngleKiQ(params.dKiQ); +} + +void TasLayoutScene::emitUpdate(const TriangleOptions& opts) +{ + if(!m_pTas || !m_pTas->IsReady() || m_bDontEmitChange) + return; + + emit tasChanged(opts); +} + +void TasLayoutScene::scaleChanged(t_real dTotalScale) +{ + if(!m_pTas) return; + m_pTas->SetZoom(dTotalScale); +} + +void TasLayoutScene::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + QGraphicsScene::mousePressEvent(pEvt); + emit nodeEvent(1); +} + +void TasLayoutScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + QGraphicsScene::mouseReleaseEvent(pEvt); + emit nodeEvent(0); +} + + +// -------------------------------------------------------------------------------- + + +TasLayoutView::TasLayoutView(QWidget* pParent) : QGraphicsView(pParent) +{ + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + setDragMode(QGraphicsView::ScrollHandDrag); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); +} + +TasLayoutView::~TasLayoutView() +{} + +void TasLayoutView::wheelEvent(QWheelEvent *pEvt) +{ +#if QT_VER>=5 + const t_real dDelta = pEvt->angleDelta().y()/8. / 150.; +#else + const t_real dDelta = pEvt->delta()/8. / 150.; +#endif + + const t_real dScale = std::pow(2., dDelta); + this->scale(dScale, dScale); + m_dTotalScale *= dScale; + emit scaleChanged(m_dTotalScale); +} + + +#include "tas_layout.moc" diff --git a/tools/taz/tas_layout.h b/tools/taz/tas_layout.h new file mode 100644 index 0000000..c451e51 --- /dev/null +++ b/tools/taz/tas_layout.h @@ -0,0 +1,181 @@ +/* + * TAS layout + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#ifndef __TAS_LAYOUT_H__ +#define __TAS_LAYOUT_H__ + +#include "tlibs/helper/flags.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" + +#include +#include +#include +#include +#include +#include +#include +#if QT_VER>=5 + #include +#endif + +#include "tasoptions.h" +#include "dialogs/RealParamDlg.h" // for RealParams struct +#include "dialogs/RecipParamDlg.h" // for RecipParams struct + + +class TasLayout; +class TasLayoutNode : public QGraphicsItem +{ + protected: + TasLayout *m_pParentItem; + + protected: + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &val) override; + + public: + TasLayoutNode(TasLayout* pSupItem); +}; + + +class TasLayoutScene; +class TasLayout : public QGraphicsItem +{ + protected: + bool m_bReady = 0; + TasLayoutScene& m_scene; + + TasLayoutNode *m_pSrc = 0; + TasLayoutNode *m_pMono = 0; + TasLayoutNode *m_pSample = 0; + TasLayoutNode *m_pAna = 0; + TasLayoutNode *m_pDet = 0; + + t_real_glob m_dMonoTwoTheta = 3.1415/2.; + t_real_glob m_dAnaTwoTheta = 3.1415/2.; + t_real_glob m_dTwoTheta = 3.1415/2.; + t_real_glob m_dTheta = 3.1415/4.; + t_real_glob m_dAngleKiQ = 3.1415/4.; + + t_real_glob m_dLenMonoSample = 150.; + t_real_glob m_dLenSampleAna = 100.; + t_real_glob m_dLenAnaDet = 50.; + t_real_glob m_dLenSample = 25.; + + t_real_glob m_dScaleFactor = 1.4; // pixels per cm for zoom == 1 + t_real_glob m_dZoom = 1.; + + bool m_bRealQVisible = 1; + bool m_bAllowChanges = 1; + + public: + t_real_glob GetMonoTwoTheta() const { return m_dMonoTwoTheta; } + t_real_glob GetMonoTheta() const { return m_dMonoTwoTheta/2.; } + t_real_glob GetAnaTwoTheta() const { return m_dAnaTwoTheta; } + t_real_glob GetAnaTheta() const { return m_dAnaTwoTheta/2.; } + t_real_glob GetSampleTwoTheta() const { return m_dTwoTheta; } + t_real_glob GetSampleTheta() const { return m_dTheta; } + t_real_glob GetLenMonoSample() const { return m_dLenMonoSample; } + t_real_glob GetLenSampleAna() const { return m_dLenSampleAna; } + t_real_glob GetLenAnaDet() const { return m_dLenAnaDet; } + + protected: + virtual QRectF boundingRect() const override; + + public: + TasLayout(TasLayoutScene& scene); + virtual ~TasLayout(); + + bool IsReady() const { return m_bReady; } + + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + void SetSampleTwoTheta(t_real_glob dTT); + void SetSampleTheta(t_real_glob dT); + void SetMonoTwoTheta(t_real_glob dTT); + void SetAnaTwoTheta(t_real_glob dTT); + void SetAngleKiQ(t_real_glob dKiQ); + + void SetReady(bool bReady) { m_bReady = bReady; } + void nodeMoved(const TasLayoutNode* pNode=0); + + void AllowChanges(bool bAllow) { m_bAllowChanges = bAllow; }; + void AllowMouseMove(bool bAllow); + + void SetZoom(t_real_glob dZoom); + t_real_glob GetZoom() const { return m_dZoom; } + + public: + std::vector GetNodes(); + std::vector GetNodeNames() const; + + t_real_glob GetScaleFactor() const { return m_dScaleFactor; } + void SetScaleFactor(t_real_glob dScale) { m_dScaleFactor = dScale; } + + void SetRealQVisible(bool bVisible); + bool GetRealQVisible() const { return m_bRealQVisible; } +}; + + +class TasLayoutScene : public QGraphicsScene +{ Q_OBJECT + protected: + TasLayout *m_pTas; + bool m_bDontEmitChange = 1; + + protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + + + public: + TasLayoutScene(QObject *pParent=nullptr); + virtual ~TasLayoutScene(); + + void SetEmitChanges(bool bEmit) { m_bDontEmitChange = !bEmit; } + void emitUpdate(const TriangleOptions& opts); + + TasLayout* GetTasLayout() { return m_pTas; } + + void emitAllParams(); + + public slots: + void triangleChanged(const TriangleOptions& opts); + void scaleChanged(t_real_glob dTotalScale); + + void recipParamsChanged(const RecipParams& params); + + signals: + // relevant parameters for triangle view + void tasChanged(const TriangleOptions& opts); + // all parameters + void paramsChanged(const RealParams& parms); + + void nodeEvent(bool bStarted); +}; + + +class TasLayoutView : public QGraphicsView +{ + Q_OBJECT + protected: + t_real_glob m_dTotalScale = 1.; + virtual void wheelEvent(QWheelEvent* pEvt) override; + + public: + TasLayoutView(QWidget* pParent = 0); + virtual ~TasLayoutView(); + + signals: + void scaleChanged(t_real_glob dTotalScale); +}; + + +#endif diff --git a/tools/taz/tasoptions.h b/tools/taz/tasoptions.h new file mode 100644 index 0000000..fb4d096 --- /dev/null +++ b/tools/taz/tasoptions.h @@ -0,0 +1,77 @@ +/* + * Scattering Triangle tool + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#ifndef __TASOPTIONS_H__ +#define __TASOPTIONS_H__ + +#include "tlibs/math/linalg.h" +#include "libs/globals.h" +#include + +namespace ublas = boost::numeric::ublas; + + +static inline ublas::vector qpoint_to_vec(const QPointF& pt) +{ + ublas::vector vec(2); + vec[0] = t_real_glob(pt.x()); + vec[1] = t_real_glob(pt.y()); + + return vec; +} + +static inline QPointF vec_to_qpoint(const ublas::vector& vec) +{ + if(vec.size() < 2) + return QPointF(0., 0.); + + return QPointF(vec[0], vec[1]); +} + +struct TriangleOptions +{ + bool bChangedTheta = 0; + bool bChangedTwoTheta = 0; + bool bChangedAnaTwoTheta = 0; + bool bChangedMonoTwoTheta = 0; + + bool bChangedMonoD = 0; + bool bChangedAnaD = 0; + + bool bChangedAngleKiVec0 = 0; + + + t_real_glob dTheta; + t_real_glob dTwoTheta; + t_real_glob dAnaTwoTheta; + t_real_glob dMonoTwoTheta; + + t_real_glob dMonoD; + t_real_glob dAnaD; + + t_real_glob dAngleKiVec0; +}; + +struct CrystalOptions +{ + bool bChangedLattice = 0; + bool bChangedLatticeAngles = 0; + bool bChangedSpacegroup = 0; + bool bChangedPlane1 = 0; + bool bChangedPlane2 = 0; + + t_real_glob dLattice[3]; + t_real_glob dLatticeAngles[3]; + std::string strSpacegroup; + t_real_glob dPlane1[3]; + t_real_glob dPlane2[3]; + + std::string strSampleName; +}; + + +#endif diff --git a/tools/taz/taz.cpp b/tools/taz/taz.cpp new file mode 100644 index 0000000..d1637c4 --- /dev/null +++ b/tools/taz/taz.cpp @@ -0,0 +1,1344 @@ +/** + * TAS tool + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#include "taz.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tlibs/math/lattice.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/string/string.h" +#include "tlibs/helper/flags.h" +#include "tlibs/file/recent.h" +#include "tlibs/log/log.h" + +namespace algo = boost::algorithm; +namespace fs = boost::filesystem; + +using t_real = t_real_glob; +const std::string TazDlg::s_strTitle = "Takin"; + + +TazDlg::TazDlg(QWidget* pParent) + : QMainWindow(pParent), m_settings("tobis_stuff", "takin"), + m_pSettingsDlg(new SettingsDlg(this, &m_settings)), + m_pStatusMsg(new QLabel(this)), + m_pCoordQStatusMsg(new QLabel(this)), + m_pCoordCursorStatusMsg(new QLabel(this)), + m_sceneRecip(this), + m_dlgRecipParam(this, &m_settings), + m_dlgRealParam(this, &m_settings), + m_pGotoDlg(new GotoDlg(this, &m_settings)) +{ + //log_debug("In ", __func__, "."); + + const bool bSmallqVisible = 0; + const bool bBZVisible = 1; + const bool bWSVisible = 1; + + this->setupUi(this); + this->setWindowTitle(s_strTitle.c_str()); + this->setFont(g_fontGen); + btnAtoms->setEnabled(g_bHasScatlens); + + if(m_settings.contains("main/geo")) + { + QByteArray geo = m_settings.value("main/geo").toByteArray(); + restoreGeometry(geo); + } + /*if(m_settings.contains("main/width") && m_settings.contains("main/height")) + { + int iW = m_settings.value("main/width").toInt(); + int iH = m_settings.value("main/height").toInt(); + resize(iW, iH); + }*/ + + m_pStatusMsg->setFrameStyle(QFrame::Panel | QFrame::Sunken); + m_pCoordQStatusMsg->setFrameStyle(QFrame::Panel | QFrame::Sunken); + m_pCoordCursorStatusMsg->setFrameStyle(QFrame::Panel | QFrame::Sunken); + for(QLabel* pLabel : {m_pStatusMsg/*, m_pCoordQStatusMsg, m_pCoordCursorStatusMsg*/}) + pLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + + QStatusBar *pStatusBar = new QStatusBar(this); + pStatusBar->addWidget(m_pStatusMsg, 1); + pStatusBar->addPermanentWidget(m_pCoordQStatusMsg, 0); + pStatusBar->addPermanentWidget(m_pCoordCursorStatusMsg, 0); + m_pCoordQStatusMsg->setMinimumWidth(350); + m_pCoordQStatusMsg->setAlignment(Qt::AlignCenter); + m_pCoordCursorStatusMsg->setMinimumWidth(325); + m_pCoordCursorStatusMsg->setAlignment(Qt::AlignCenter); + this->setStatusBar(pStatusBar); + + // -------------------------------------------------------------------------------- + + m_vecEdits_real = + { + editA, editB, editC, + editAlpha, editBeta, editGamma + }; + m_vecEdits_recip = + { + editARecip, editBRecip, editCRecip, + editAlphaRecip, editBetaRecip, editGammaRecip + }; + + m_vecEdits_plane = + { + editScatX0, editScatX1, editScatX2, + editScatY0, editScatY1, editScatY2, + + editRealX0, editRealX1, editRealX2, + editRealY0, editRealY1, editRealY2, + }; + m_vecEdits_monoana = + { + editMonoD, editAnaD + }; + + //m_vecSpinBoxesSample = { spinRotPhi, spinRotTheta, spinRotPsi }; + m_vecCheckBoxesSenses = { checkSenseM, checkSenseS, checkSenseA }; + + + m_vecEditNames_real = + { + "sample/a", "sample/b", "sample/c", + "sample/alpha", "sample/beta", "sample/gamma" + }; + m_vecEditNames_recip = + { + "sample/a_recip", "sample/b_recip", "sample/c_recip", + "sample/alpha_recip", "sample/beta_recip", "sample/gamma_recip" + }; + m_vecEditNames_plane = + { + "plane/x0", "plane/x1", "plane/x2", + "plane/y0", "plane/y1", "plane/y2", + + "plane/real_x0", "plane/real_x1", "plane/real_x2", + "plane/real_y0", "plane/real_y1", "plane/real_y2", + }; + m_vecEditNames_monoana = + { + "tas/mono_d", "tas/ana_d" + }; + + m_vecSpinBoxNamesSample = {"sample/phi", "sample/theta", "sample/psi"}; + m_vecCheckBoxNamesSenses = {"tas/sense_m", "tas/sense_s", "tas/sense_a"}; + + + // recip + m_pviewRecip = new ScatteringTriangleView(groupRecip); + groupRecip->addTab(m_pviewRecip, "Reciprocal Lattice"); + + m_pviewProjRecip = new ProjLatticeView(groupRecip); + groupRecip->addTab(m_pviewProjRecip, "Projection"); + + m_pviewRecip->setScene(&m_sceneRecip); + m_pviewProjRecip->setScene(&m_sceneProjRecip); + + if(m_settings.contains("main/recip_tab")) + groupRecip->setCurrentIndex(m_settings.value("main/recip_tab").value()); + + + // real + m_pviewRealLattice = new LatticeView(groupReal); + groupReal->addTab(m_pviewRealLattice, "Real Lattice"); + + m_pviewReal = new TasLayoutView(groupReal); + groupReal->addTab(m_pviewReal, "TAS Instrument"); + + m_pviewTof = new TofLayoutView(groupReal); + groupReal->addTab(m_pviewTof, "TOF Instrument"); + + m_pviewRealLattice->setScene(&m_sceneRealLattice); + m_pviewReal->setScene(&m_sceneReal); + m_pviewTof->setScene(&m_sceneTof); + + if(m_settings.contains("main/real_tab")) + groupReal->setCurrentIndex(m_settings.value("main/real_tab").value()); + + + + QObject::connect(m_pSettingsDlg, SIGNAL(SettingsChanged()), this, SLOT(SettingsChanged())); + + QObject::connect(&m_sceneReal, SIGNAL(nodeEvent(bool)), this, SLOT(RealNodeEvent(bool))); + QObject::connect(&m_sceneRecip, SIGNAL(nodeEvent(bool)), this, SLOT(RecipNodeEvent(bool))); + QObject::connect(&m_sceneTof, SIGNAL(nodeEvent(bool)), this, SLOT(TofNodeEvent(bool))); + + // TAS + QObject::connect(&m_sceneRecip, SIGNAL(triangleChanged(const TriangleOptions&)), + &m_sceneReal, SLOT(triangleChanged(const TriangleOptions&))); + QObject::connect(&m_sceneReal, SIGNAL(tasChanged(const TriangleOptions&)), + &m_sceneRecip, SLOT(tasChanged(const TriangleOptions&))); + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + &m_sceneReal, SLOT(recipParamsChanged(const RecipParams&))); + + // TOF + QObject::connect(&m_sceneRecip, SIGNAL(triangleChanged(const TriangleOptions&)), + &m_sceneTof, SLOT(triangleChanged(const TriangleOptions&))); + QObject::connect(&m_sceneTof, SIGNAL(tasChanged(const TriangleOptions&)), + &m_sceneRecip, SLOT(tasChanged(const TriangleOptions&))); + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + &m_sceneTof, SLOT(recipParamsChanged(const RecipParams&))); + + // connections between instruments + QObject::connect(&m_sceneTof, SIGNAL(tasChanged(const TriangleOptions&)), + &m_sceneReal, SLOT(triangleChanged(const TriangleOptions&))); + QObject::connect(&m_sceneReal, SIGNAL(tasChanged(const TriangleOptions&)), + &m_sceneTof, SLOT(triangleChanged(const TriangleOptions&))); + + // scale factor + if(m_pviewRecip) + QObject::connect(m_pviewRecip, SIGNAL(scaleChanged(t_real_glob)), + &m_sceneRecip, SLOT(scaleChanged(t_real_glob))); + if(m_pviewProjRecip) + QObject::connect(m_pviewProjRecip, SIGNAL(scaleChanged(t_real_glob)), + &m_sceneProjRecip, SLOT(scaleChanged(t_real_glob))); + if(m_pviewRealLattice) + QObject::connect(m_pviewRealLattice, SIGNAL(scaleChanged(t_real_glob)), + &m_sceneRealLattice, SLOT(scaleChanged(t_real_glob))); + if(m_pviewReal) + QObject::connect(m_pviewReal, SIGNAL(scaleChanged(t_real_glob)), + &m_sceneReal, SLOT(scaleChanged(t_real_glob))); + if(m_pviewTof) + QObject::connect(m_pviewTof, SIGNAL(scaleChanged(t_real_glob)), + &m_sceneTof, SLOT(scaleChanged(t_real_glob))); + + // parameter dialogs + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + &m_dlgRecipParam, SLOT(paramsChanged(const RecipParams&))); + QObject::connect(&m_sceneReal, SIGNAL(paramsChanged(const RealParams&)), + &m_dlgRealParam, SLOT(paramsChanged(const RealParams&))); + + // cursor position + QObject::connect(&m_sceneRecip, SIGNAL(coordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob)), + this, SLOT(RecipCoordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob))); + QObject::connect(&m_sceneProjRecip, SIGNAL(coordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob)), + this, SLOT(RecipCoordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob))); + QObject::connect(&m_sceneRealLattice, SIGNAL(coordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob)), + this, SLOT(RealCoordsChanged(t_real_glob, t_real_glob, t_real_glob, bool, t_real_glob, t_real_glob, t_real_glob))); + + QObject::connect(&m_sceneRecip, SIGNAL(spurionInfo(const tl::ElasticSpurion&, const std::vector>&, const std::vector>&)), + this, SLOT(spurionInfo(const tl::ElasticSpurion&, const std::vector>&, const std::vector>&))); + + QObject::connect(m_pGotoDlg, SIGNAL(vars_changed(const CrystalOptions&, const TriangleOptions&)), + this, SLOT(VarsChanged(const CrystalOptions&, const TriangleOptions&))); + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + m_pGotoDlg, SLOT(RecipParamsChanged(const RecipParams&))); + + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + this, SLOT(recipParamsChanged(const RecipParams&))); + + + for(QLineEdit* pEdit : m_vecEdits_monoana) + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(UpdateDs())); + + for(QLineEdit* pEdit : m_vecEdits_real) + { + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CheckCrystalType())); + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcPeaks())); + } + + for(QLineEdit* pEdit : m_vecEdits_plane) + { + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcPeaks())); + } + + //for(QDoubleSpinBox* pSpin : m_vecSpinBoxesSample) + // QObject::connect(pSpin, SIGNAL(valueChanged(t_real)), this, SLOT(CalcPeaks())); + + for(QLineEdit* pEdit : m_vecEdits_recip) + { + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CheckCrystalType())); + QObject::connect(pEdit, SIGNAL(textEdited(const QString&)), this, SLOT(CalcPeaksRecip())); + } + + QObject::connect(checkSenseM, SIGNAL(stateChanged(int)), this, SLOT(UpdateMonoSense())); + QObject::connect(checkSenseS, SIGNAL(stateChanged(int)), this, SLOT(UpdateSampleSense())); + QObject::connect(checkSenseA, SIGNAL(stateChanged(int)), this, SLOT(UpdateAnaSense())); + + QObject::connect(editSpaceGroupsFilter, SIGNAL(textEdited(const QString&)), this, SLOT(RepopulateSpaceGroups())); + QObject::connect(comboSpaceGroups, SIGNAL(currentIndexChanged(int)), this, SLOT(SetCrystalType())); + QObject::connect(comboSpaceGroups, SIGNAL(currentIndexChanged(int)), this, SLOT(CalcPeaks())); + QObject::connect(checkPowder, SIGNAL(stateChanged(int)), this, SLOT(CalcPeaks())); + + QObject::connect(btnAtoms, SIGNAL(clicked(bool)), this, SLOT(ShowAtomsDlg())); + + + + // -------------------------------------------------------------------------------- + // file menu + QMenu *pMenuFile = new QMenu("File", this); + + QAction *pNew = new QAction("New", this); + pNew->setIcon(load_icon("res/document-new.svg")); + pMenuFile->addAction(pNew); + + pMenuFile->addSeparator(); + + QAction *pLoad = new QAction("Load...", this); + pLoad->setIcon(load_icon("res/document-open.svg")); + pMenuFile->addAction(pLoad); + + m_pMenuRecent = new QMenu("Recently Loaded", this); + tl::RecentFiles recent(&m_settings, "main/recent"); + m_pMapperRecent = new QSignalMapper(m_pMenuRecent); + QObject::connect(m_pMapperRecent, SIGNAL(mapped(const QString&)), + this, SLOT(LoadFile(const QString&))); + recent.FillMenu(m_pMenuRecent, m_pMapperRecent); + pMenuFile->addMenu(m_pMenuRecent); + + QAction *pSave = new QAction("Save", this); + pSave->setIcon(load_icon("res/document-save.svg")); + pMenuFile->addAction(pSave); + + QAction *pSaveAs = new QAction("Save as...", this); + pSaveAs->setIcon(load_icon("res/document-save-as.svg")); + pMenuFile->addAction(pSaveAs); + + pMenuFile->addSeparator(); + + QAction *pImport = new QAction("Import...", this); + pImport->setIcon(load_icon("res/drive-harddisk.svg")); + pMenuFile->addAction(pImport); + + m_pMenuRecentImport = new QMenu("Recently Imported", this); + tl::RecentFiles recentimport(&m_settings, "main/recent_import"); + m_pMapperRecentImport = new QSignalMapper(m_pMenuRecentImport); + QObject::connect(m_pMapperRecentImport, SIGNAL(mapped(const QString&)), + this, SLOT(ImportFile(const QString&))); + recentimport.FillMenu(m_pMenuRecentImport, m_pMapperRecentImport); + pMenuFile->addMenu(m_pMenuRecentImport); + + pMenuFile->addSeparator(); + + QAction *pSettings = new QAction("Settings...", this); + pSettings->setIcon(load_icon("res/preferences-system.svg")); + pMenuFile->addAction(pSettings); + + pMenuFile->addSeparator(); + + QAction *pExit = new QAction("Exit", this); + pExit->setIcon(load_icon("res/system-log-out.svg")); + pMenuFile->addAction(pExit); + + + // -------------------------------------------------------------------------------- + // recip menu + m_pMenuViewRecip = new QMenu("Reciprocal Space", this); + + m_pGoto = new QAction("Go to Position...", this); + m_pGoto->setIcon(load_icon("res/goto.svg")); + m_pMenuViewRecip->addAction(m_pGoto); + + QAction *pRecipParams = new QAction("Information...", this); + m_pMenuViewRecip->addAction(pRecipParams); + m_pMenuViewRecip->addSeparator(); + + m_pSmallq = new QAction("Show Reduced Scattering Vector q", this); + m_pSmallq->setIcon(load_icon("res/q.svg")); + m_pSmallq->setCheckable(1); + m_pSmallq->setChecked(bSmallqVisible); + m_pMenuViewRecip->addAction(m_pSmallq); + + m_pSnapSmallq = new QAction("Snap G to Bragg Peak", this); + m_pSnapSmallq->setCheckable(1); + m_pSnapSmallq->setChecked(m_sceneRecip.getSnapq()); + m_pMenuViewRecip->addAction(m_pSnapSmallq); + + QAction *pKeepAbsKiKf = new QAction("Keep |ki| and |kf| Fixed", this); + pKeepAbsKiKf->setCheckable(1); + pKeepAbsKiKf->setChecked(m_sceneRecip.getKeepAbsKiKf()); + m_pMenuViewRecip->addAction(pKeepAbsKiKf); + + m_pBZ = new QAction("Show First Brillouin Zone", this); + m_pBZ->setIcon(load_icon("res/brillouin.svg")); + m_pBZ->setCheckable(1); + m_pBZ->setChecked(bBZVisible); + m_pMenuViewRecip->addAction(m_pBZ); + + + QMenu *pMenuEwald = new QMenu("Ewald Sphere", this); + QActionGroup *pGroupEwald = new QActionGroup(this); + m_pEwaldSphereNone = new QAction("Disabled", this); + m_pEwaldSphereKi = new QAction("Around ki", this); + m_pEwaldSphereKf = new QAction("Around kf", this); + for(QAction* pAct : {m_pEwaldSphereNone, m_pEwaldSphereKi, m_pEwaldSphereKf}) + { + pAct->setCheckable(1); + pGroupEwald->addAction(pAct); + } + + m_pEwaldSphereKf->setChecked(1); + pMenuEwald->addActions(pGroupEwald->actions()); + m_pMenuViewRecip->addMenu(pMenuEwald); + + + m_pMenuViewRecip->addSeparator(); + + QMenu *pMenuProj = new QMenu("Projection", this); + pMenuProj->setTearOffEnabled(1); + QActionGroup *pGroupProj = new QActionGroup(this); + + m_pProjGnom = new QAction("Gnomonic", this); + m_pProjStereo = new QAction("Stereographic", this); + m_pProjPara = new QAction("Parallel", this); + m_pProjPersp = new QAction("Perspectivic", this); + + for(QAction *pAct : {m_pProjGnom, m_pProjStereo, m_pProjPara, m_pProjPersp}) + { + pAct->setCheckable(1); + pGroupProj->addAction(pAct); + } + + m_pProjStereo->setChecked(1); + pMenuProj->addActions(pGroupProj->actions()); + + m_pMenuViewRecip->addMenu(pMenuProj); + +#if !defined NO_3D + QAction *pView3D = new QAction("3D View...", this); + //pView3D->setIcon(QIcon::fromTheme("applications-graphics")); + m_pMenuViewRecip->addAction(pView3D); +#endif + + m_pMenuViewRecip->addSeparator(); + + QAction *pRecipExport = new QAction("Export Lattice Graphics...", this); + pRecipExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewRecip->addAction(pRecipExport); + + QAction *pProjExport = new QAction("Export Projection Graphics...", this); + pProjExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewRecip->addAction(pProjExport); + +#ifdef USE_GIL + QAction *pBZExport = new QAction("Export Brillouin Zone Image...", this); + pBZExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewRecip->addAction(pBZExport); +#endif + + + // -------------------------------------------------------------------------------- + // real menu + m_pMenuViewReal = new QMenu("Real Space", this); + m_pMenuViewReal->addAction(m_pGoto); + + QAction *pRealParams = new QAction("Information...", this); + m_pMenuViewReal->addAction(pRealParams); + + m_pMenuViewReal->addSeparator(); + + m_pShowRealQDir = new QAction("Show Q Direction", this); + m_pShowRealQDir->setCheckable(1); + m_pShowRealQDir->setChecked(m_sceneReal.GetTasLayout()->GetRealQVisible()); + m_pMenuViewReal->addAction(m_pShowRealQDir); + + m_pWS = new QAction("Show Wigner-Seitz Cell", this); + m_pWS->setIcon(load_icon("res/brillouin.svg")); + m_pWS->setCheckable(1); + m_pWS->setChecked(bWSVisible); + m_pMenuViewReal->addAction(m_pWS); + + m_pMenuViewReal->addSeparator(); + + QAction *pRealLatticeExport = new QAction("Export Lattice Graphics...", this); + pRealLatticeExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewReal->addAction(pRealLatticeExport); + + QAction *pRealExport = new QAction("Export TAS Layout...", this); + pRealExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewReal->addAction(pRealExport); + + QAction *pTofExport = new QAction("Export TOF Layout...", this); + pTofExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewReal->addAction(pTofExport); + +#ifdef USE_GIL + QAction *pWSExport = new QAction("Export Wigner-Seitz Cell Image...", this); + pWSExport->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewReal->addAction(pWSExport); +#endif + + QAction *pExportUC = new QAction("Export Unit Cell Model...", this); + pExportUC->setIcon(load_icon("res/image-x-generic.svg")); + m_pMenuViewReal->addAction(pExportUC); + + + // -------------------------------------------------------------------------------- + // resolution menu + QMenu *pMenuReso = new QMenu("Resolution", this); + + QAction *pResoParams = new QAction("Parameters...", this); + pResoParams->setIcon(load_icon("res/accessories-calculator.svg")); + pMenuReso->addAction(pResoParams); + + pMenuReso->addSeparator(); + + QAction *pResoEllipses = new QAction("Ellipses...", this); + pResoEllipses->setIcon(load_icon("res/ellipses.svg")); + pMenuReso->addAction(pResoEllipses); + +#if !defined NO_3D + QAction *pResoEllipses3D = new QAction("3D Ellipsoids...", this); + pMenuReso->addAction(pResoEllipses3D); +#endif + + pMenuReso->addSeparator(); + + QAction *pResoConv = new QAction("Convolution...", this); + pMenuReso->addAction(pResoConv); + + + // -------------------------------------------------------------------------------- + // calc menu + QMenu *pMenuCalc = new QMenu("Calculation", this); + + QAction *pNeutronProps = new QAction("Neutron Properties...", this); + pNeutronProps->setIcon(load_icon("res/x-office-spreadsheet-template.svg")); + pMenuCalc->addAction(pNeutronProps); + + pMenuCalc->addSeparator(); + + QAction *pPowder = new QAction("Powder Lines...", this); + pPowder->setIcon(load_icon("res/weather-snow.svg")); + pMenuCalc->addAction(pPowder); + + QAction *pDW = new QAction("Scattering Factors...", this); + pMenuCalc->addAction(pDW); + + QAction *pFormfactor = nullptr; + if(g_bHasFormfacts && g_bHasScatlens) + { + pFormfactor = new QAction("Form Factors...", this); + pMenuCalc->addAction(pFormfactor); + } + + QAction *pSgList = new QAction("Space Group Types...", this); + pMenuCalc->addAction(pSgList); + + QAction *pDisp = new QAction("Dispersions...", this); + //pDisp->setIcon(load_icon("disp.svg")); + pMenuCalc->addAction(pDisp); + + pMenuCalc->addSeparator(); + + QAction *pDynPlane = new QAction("Kinematic Plane...", this); + pMenuCalc->addAction(pDynPlane); + + QAction *pSpuri = new QAction("Spurious Scattering...", this); + pMenuCalc->addAction(pSpuri); + + +#if !defined NO_NET + // -------------------------------------------------------------------------------- + // network menu + QMenu *pMenuNet = new QMenu("Network", this); + + QAction *pConn = new QAction("Connect to Instrument...", this); + pConn->setIcon(load_icon("res/network-transmit-receive.svg")); + pMenuNet->addAction(pConn); + + QAction *pDisconn = new QAction("Disconnect", this); + pDisconn->setIcon(load_icon("res/network-offline.svg")); + pMenuNet->addAction(pDisconn); + + QAction *pNetCache = new QAction("Network Cache...", this); + pMenuNet->addSeparator(); + pMenuNet->addAction(pNetCache); + + QAction *pNetRefresh = new QAction("Refresh", this); + pNetRefresh->setIcon(load_icon("res/view-refresh.svg")); + pMenuNet->addSeparator(); + pMenuNet->addAction(pNetRefresh); +#endif + + + // -------------------------------------------------------------------------------- + // tools menu + QMenu *pMenuTools = new QMenu("Tools", this); + + QAction *pScanViewer = new QAction("Scan Viewer...", this); + pMenuTools->addAction(pScanViewer); + + + + // -------------------------------------------------------------------------------- + // help menu + QMenu *pMenuHelp = new QMenu("Help", this); + + QAction *pHelp = new QAction("Show Help...", this); + pHelp->setIcon(load_icon("res/help-browser.svg")); + pMenuHelp->addAction(pHelp); + + pMenuHelp->addSeparator(); + + QAction *pAboutQt = new QAction("About Qt...", this); + //pAboutQt->setIcon(QIcon::fromTheme("help-about")); + pMenuHelp->addAction(pAboutQt); + + //pMenuHelp->addSeparator(); + QAction *pAbout = new QAction("About Takin...", this); + pAbout->setIcon(load_icon("res/dialog-information.svg")); + pMenuHelp->addAction(pAbout); + + + + // -------------------------------------------------------------------------------- + QMenuBar *pMenuBar = new QMenuBar(this); + pMenuBar->addMenu(pMenuFile); + pMenuBar->addMenu(m_pMenuViewRecip); + pMenuBar->addMenu(m_pMenuViewReal); + pMenuBar->addMenu(pMenuReso); + pMenuBar->addMenu(pMenuCalc); + pMenuBar->addMenu(pMenuTools); +#if !defined NO_NET + pMenuBar->addMenu(pMenuNet); +#endif + pMenuBar->addMenu(pMenuHelp); + + + QObject::connect(pNew, SIGNAL(triggered()), this, SLOT(New())); + QObject::connect(pLoad, SIGNAL(triggered()), this, SLOT(Load())); + QObject::connect(pSave, SIGNAL(triggered()), this, SLOT(Save())); + QObject::connect(pSaveAs, SIGNAL(triggered()), this, SLOT(SaveAs())); + QObject::connect(pImport, SIGNAL(triggered()), this, SLOT(Import())); + QObject::connect(pScanViewer, SIGNAL(triggered()), this, SLOT(ShowScanViewer())); + QObject::connect(pSettings, SIGNAL(triggered()), this, SLOT(ShowSettingsDlg())); + QObject::connect(pExit, SIGNAL(triggered()), this, SLOT(close())); + + QObject::connect(m_pSmallq, SIGNAL(toggled(bool)), this, SLOT(EnableSmallq(bool))); + QObject::connect(m_pBZ, SIGNAL(toggled(bool)), this, SLOT(EnableBZ(bool))); + QObject::connect(m_pWS, SIGNAL(toggled(bool)), this, SLOT(EnableWS(bool))); + + for(QAction* pAct : {m_pEwaldSphereNone, m_pEwaldSphereKi, m_pEwaldSphereKf}) + QObject::connect(pAct, SIGNAL(triggered()), this, SLOT(ShowEwaldSphere())); + + QObject::connect(m_pShowRealQDir, SIGNAL(toggled(bool)), this, SLOT(EnableRealQDir(bool))); + + QObject::connect(m_pSnapSmallq, SIGNAL(toggled(bool)), &m_sceneRecip, SLOT(setSnapq(bool))); + QObject::connect(pKeepAbsKiKf, SIGNAL(toggled(bool)), &m_sceneRecip, SLOT(setKeepAbsKiKf(bool))); + + QObject::connect(pRecipParams, SIGNAL(triggered()), this, SLOT(ShowRecipParams())); + QObject::connect(pRealParams, SIGNAL(triggered()), this, SLOT(ShowRealParams())); + + for(QAction *pProj : {m_pProjGnom, m_pProjStereo, m_pProjPara, m_pProjPersp}) + QObject::connect(pProj, SIGNAL(triggered()), this, SLOT(RecipProjChanged())); + +#if !defined NO_3D + QObject::connect(pView3D, SIGNAL(triggered()), this, SLOT(Show3D())); + QObject::connect(pResoEllipses3D, SIGNAL(triggered()), this, SLOT(ShowResoEllipses3D())); +#endif + + QObject::connect(pRecipExport, SIGNAL(triggered()), this, SLOT(ExportRecip())); + QObject::connect(pProjExport, SIGNAL(triggered()), this, SLOT(ExportProj())); + QObject::connect(pRealExport, SIGNAL(triggered()), this, SLOT(ExportReal())); + QObject::connect(pTofExport, SIGNAL(triggered()), this, SLOT(ExportTof())); + QObject::connect(pRealLatticeExport, SIGNAL(triggered()), this, SLOT(ExportRealLattice())); + + QObject::connect(pExportUC, SIGNAL(triggered()), this, SLOT(ExportUCModel())); + +#ifdef USE_GIL + QObject::connect(pBZExport, SIGNAL(triggered()), this, SLOT(ExportBZImage())); + QObject::connect(pWSExport, SIGNAL(triggered()), this, SLOT(ExportWSImage())); +#endif + + QObject::connect(pResoParams, SIGNAL(triggered()), this, SLOT(ShowResoParams())); + QObject::connect(pResoEllipses, SIGNAL(triggered()), this, SLOT(ShowResoEllipses())); + QObject::connect(pResoConv, SIGNAL(triggered()), this, SLOT(ShowResoConv())); + + QObject::connect(pNeutronProps, SIGNAL(triggered()), this, SLOT(ShowNeutronDlg())); + QObject::connect(m_pGoto, SIGNAL(triggered()), this, SLOT(ShowGotoDlg())); + QObject::connect(pPowder, SIGNAL(triggered()), this, SLOT(ShowPowderDlg())); + QObject::connect(pDisp, SIGNAL(triggered()), this, SLOT(ShowDispDlg())); + QObject::connect(pSpuri, SIGNAL(triggered()), this, SLOT(ShowSpurions())); + QObject::connect(pDW, SIGNAL(triggered()), this, SLOT(ShowDWDlg())); + QObject::connect(pDynPlane, SIGNAL(triggered()), this, SLOT(ShowDynPlaneDlg())); + +#if !defined NO_NET + QObject::connect(pConn, SIGNAL(triggered()), this, SLOT(ShowConnectDlg())); + QObject::connect(pDisconn, SIGNAL(triggered()), this, SLOT(Disconnect())); + QObject::connect(pNetRefresh, SIGNAL(triggered()), this, SLOT(NetRefresh())); + QObject::connect(pNetCache, SIGNAL(triggered()), this, SLOT(ShowNetCache())); +#endif + + QObject::connect(pSgList, SIGNAL(triggered()), this, SLOT(ShowSgListDlg())); + + if(pFormfactor) + QObject::connect(pFormfactor, SIGNAL(triggered()), this, SLOT(ShowFormfactorDlg())); + + QObject::connect(pHelp, SIGNAL(triggered()), this, SLOT(ShowHelp())); + QObject::connect(pAbout, SIGNAL(triggered()), this, SLOT(ShowAbout())); + QObject::connect(pAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + + + setMenuBar(pMenuBar); + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // context menus + if(m_pviewRecip) m_pviewRecip->setContextMenuPolicy(Qt::CustomContextMenu); + if(m_pviewProjRecip) m_pviewProjRecip->setContextMenuPolicy(Qt::CustomContextMenu); + if(m_pviewRealLattice) m_pviewRealLattice->setContextMenuPolicy(Qt::CustomContextMenu); + if(m_pviewReal) m_pviewReal->setContextMenuPolicy(Qt::CustomContextMenu); + if(m_pviewTof) m_pviewTof->setContextMenuPolicy(Qt::CustomContextMenu); + + if(m_pviewRecip) + QObject::connect(m_pviewRecip, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(RecipContextMenu(const QPoint&))); + if(m_pviewProjRecip) + QObject::connect(m_pviewProjRecip, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(RecipContextMenu(const QPoint&))); + if(m_pviewRealLattice) + QObject::connect(m_pviewRealLattice, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(RealContextMenu(const QPoint&))); + if(m_pviewReal) + QObject::connect(m_pviewReal, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(RealContextMenu(const QPoint&))); + if(m_pviewTof) + QObject::connect(m_pviewTof, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(RealContextMenu(const QPoint&))); + + + // -------------------------------------------------------------------------------- + // tool bars + QToolBar *pFileTools = new QToolBar(this); + pFileTools->setWindowTitle("File"); + pFileTools->addAction(pNew); + pFileTools->addAction(pLoad); + pFileTools->addAction(pImport); + pFileTools->addAction(pSave); + pFileTools->addAction(pSaveAs); + addToolBar(pFileTools); + + QToolBar *pRecipTools = new QToolBar(this); + pRecipTools->setWindowTitle("Reciprocal Space"); + pRecipTools->addAction(m_pGoto); + pRecipTools->addAction(m_pSmallq); + pRecipTools->addAction(m_pBZ); + //pRecipTools->addAction(m_pEwaldSphere); + addToolBar(pRecipTools); + + QToolBar *pResoTools = new QToolBar(this); + pResoTools->setWindowTitle("Resolution"); + pResoTools->addAction(pResoParams); + pResoTools->addAction(pResoEllipses); + addToolBar(pResoTools); + + QToolBar *pCalcTools = new QToolBar(this); + pCalcTools->setWindowTitle("Calculation"); + pCalcTools->addAction(pNeutronProps); + pCalcTools->addAction(pPowder); + addToolBar(pCalcTools); + +#if !defined NO_NET + QToolBar *pNetTools = new QToolBar(this); + pNetTools->setWindowTitle("Network"); + pNetTools->addAction(pConn); + pNetTools->addAction(pDisconn); + pNetTools->addAction(pNetRefresh); + addToolBar(pNetTools); +#endif + + // -------------------------------------------------------------------------------- + + + RepopulateSpaceGroups(); + + unsigned int iMaxPeaks = m_settings.value("main/max_peaks", 10).toUInt(); + + m_sceneRecip.GetTriangle()->SetMaxPeaks(iMaxPeaks); + m_sceneRecip.GetTriangle()->SetPlaneDistTolerance(s_dPlaneDistTolerance); + + m_sceneProjRecip.GetLattice()->SetMaxPeaks(iMaxPeaks/2); + + m_sceneRealLattice.GetLattice()->SetMaxPeaks(iMaxPeaks); + m_sceneRealLattice.GetLattice()->SetPlaneDistTolerance(s_dPlaneDistTolerance); + +#if !defined NO_3D + if(m_pRecip3d) + { + m_pRecip3d->SetMaxPeaks((t_real)iMaxPeaks); + m_pRecip3d->SetPlaneDistTolerance(s_dPlaneDistTolerance); + } +#endif + + m_bReady = 1; + UpdateDs(); + CalcPeaks(); + + + m_sceneRecip.GetTriangle()->SetqVisible(bSmallqVisible); + m_sceneRecip.GetTriangle()->SetBZVisible(bBZVisible); + m_sceneRecip.GetTriangle()->SetEwaldSphereVisible(EWALD_KF); + m_sceneRealLattice.GetLattice()->SetWSVisible(bWSVisible); + m_sceneRecip.emitUpdate(); + //m_sceneRecip.emitAllParams(); + + setAcceptDrops(1); +} + +TazDlg::~TazDlg() +{ + //log_debug("In ", __func__, "."); + DeleteDialogs(); + + // don't delete non-optional sub-modules in DeleteDialogs() + if(m_pGotoDlg) { delete m_pGotoDlg; m_pGotoDlg = 0; } + if(m_pSettingsDlg) { delete m_pSettingsDlg; m_pSettingsDlg = 0; } + + if(m_pviewRecip) { delete m_pviewRecip; m_pviewRecip = 0; } + if(m_pviewProjRecip) { delete m_pviewProjRecip; m_pviewProjRecip = 0; } + if(m_pviewRealLattice) { delete m_pviewRealLattice; m_pviewRealLattice = 0; } + if(m_pviewReal) { delete m_pviewReal; m_pviewReal = 0; } + if(m_pviewTof) { delete m_pviewTof; m_pviewTof = 0; } + + comboSpaceGroups->clear(); +} + +void TazDlg::DeleteDialogs() +{ + if(m_pAboutDlg) { delete m_pAboutDlg; m_pAboutDlg = 0; } + if(m_pEllipseDlg) { delete m_pEllipseDlg; m_pEllipseDlg = 0; } + if(m_pReso) { delete m_pReso; m_pReso = 0; } + if(m_pConvoDlg) { delete m_pConvoDlg; m_pConvoDlg = 0; } + if(m_pSpuri) { delete m_pSpuri; m_pSpuri = 0; } + if(m_pNeutronDlg) { delete m_pNeutronDlg; m_pNeutronDlg = 0; } + if(m_pPowderDlg) { delete m_pPowderDlg; m_pPowderDlg = 0; } + if(m_pDispDlg) { delete m_pDispDlg; m_pDispDlg = 0; } + if(m_pDWDlg) { delete m_pDWDlg; m_pDWDlg = 0; } + if(m_pDynPlaneDlg) { delete m_pDynPlaneDlg; m_pDynPlaneDlg = 0; } + if(m_pScanViewer) { delete m_pScanViewer; m_pScanViewer = nullptr; } + if(m_pAtomsDlg) { delete m_pAtomsDlg; m_pAtomsDlg = nullptr; } + +#if !defined NO_3D + if(m_pRecip3d) { delete m_pRecip3d; m_pRecip3d = 0; } + if(m_pEllipseDlg3D) { delete m_pEllipseDlg3D; m_pEllipseDlg3D = 0; } +#endif + +#if !defined NO_NET + if(m_pSrvDlg) { delete m_pSrvDlg; m_pSrvDlg = 0; } + if(m_pNetCacheDlg) { delete m_pNetCacheDlg; m_pNetCacheDlg = 0; } + if(m_pNetCache) { delete m_pNetCache; m_pNetCache = 0; } +#endif + + if(m_pSgListDlg) { delete m_pSgListDlg; m_pSgListDlg = 0; } + if(m_pFormfactorDlg) { delete m_pFormfactorDlg; m_pFormfactorDlg = 0; } +} + +void TazDlg::SettingsChanged() +{ + setFont(g_fontGen); + + m_sceneReal.update(); + m_sceneTof.update(); + m_sceneRealLattice.update(); + m_sceneRecip.update(); +} + + +void TazDlg::keyPressEvent(QKeyEvent *pEvt) +{ + // x rotation + if(pEvt->key() == Qt::Key_8) + RotatePlane(0, tl::d2r(-5.)); + else if(pEvt->key() == Qt::Key_2) + RotatePlane(0, tl::d2r(5.)); + + // y rotation + else if(pEvt->key() == Qt::Key_4) + RotatePlane(1, tl::d2r(-5.)); + else if(pEvt->key() == Qt::Key_6) + RotatePlane(1, tl::d2r(5.)); + + // z rotation + else if(pEvt->key() == Qt::Key_9) + RotatePlane(2, tl::d2r(-5.)); + else if(pEvt->key() == Qt::Key_7) + RotatePlane(2, tl::d2r(5.)); + + QMainWindow::keyPressEvent(pEvt); +} + +void TazDlg::keyReleaseEvent(QKeyEvent *pEvt) +{ + QMainWindow::keyReleaseEvent(pEvt); +} + + +void TazDlg::showEvent(QShowEvent *pEvt) +{ + QMainWindow::showEvent(pEvt); + + static bool bInitialShow = 1; + if(bInitialShow) + { + bInitialShow = 0; + + if(m_pviewRecip) m_pviewRecip->centerOn(m_sceneRecip.GetTriangle()->GetGfxMid()); + if(m_pviewProjRecip) m_pviewProjRecip->centerOn(0.,0.); + if(m_pviewReal) m_pviewReal->centerOn(m_sceneReal.GetTasLayout()); + if(m_pviewTof) m_pviewTof->centerOn(m_sceneTof.GetTofLayout()); + if(m_pviewRealLattice) m_pviewRealLattice->centerOn(0.,0.); + + /*for(QScrollBar* pSB : { + m_pviewRealLattice->horizontalScrollBar(), + m_pviewRealLattice->verticalScrollBar(), + m_pviewReal->horizontalScrollBar(), + m_pviewReal->verticalScrollBar(), + m_pviewRecip->horizontalScrollBar(), + m_pviewRecip->verticalScrollBar() }) + pSB->setValue(pSB->minimum() + (pSB->maximum()-pSB->minimum())/2);*/ + } +} + +void TazDlg::dragEnterEvent(QDragEnterEvent *pEvt) +{ + if(pEvt) pEvt->accept(); +} + +void TazDlg::dropEvent(QDropEvent *pEvt) +{ + if(!pEvt) return; + const QMimeData* pMime = pEvt->mimeData(); + if(!pMime) return; + + std::string strFiles = pMime->text().toStdString(); + std::vector vecFiles; + tl::get_tokens(strFiles, "\n", vecFiles); + if(vecFiles.size() > 1) + tl::log_warn("More than one file dropped, using first one."); + + if(vecFiles.size() >= 1) + { + std::string& strFile = vecFiles[0]; + tl::trim(strFile); + + const std::string strHead = "file://"; + if(algo::starts_with(strFile, strHead)) + algo::replace_head(strFile, strHead.length(), ""); + //tl::log_debug("dropped: ", strFile); + + Load(strFile.c_str()); + } +} + +void TazDlg::closeEvent(QCloseEvent* pEvt) +{ + m_bReady = 0; + + //m_settings.setValue("main/width", this->width()); + //m_settings.setValue("main/height", this->height()); + m_settings.setValue("main/geo", saveGeometry()); + m_settings.setValue("main/recip_tab", groupRecip->currentIndex()); + m_settings.setValue("main/real_tab", groupReal->currentIndex()); + + QMainWindow::closeEvent(pEvt); +} + + +void TazDlg::ShowNeutronDlg() +{ + if(!m_pNeutronDlg) + m_pNeutronDlg = new NeutronDlg(this, &m_settings); + + m_pNeutronDlg->show(); + m_pNeutronDlg->activateWindow(); +} + +void TazDlg::InitGoto() +{ + if(!m_pGotoDlg) + m_pGotoDlg = new GotoDlg(this, &m_settings); +} + +void TazDlg::ShowGotoDlg() +{ + InitGoto(); + m_pGotoDlg->show(); + m_pGotoDlg->activateWindow(); +} + +void TazDlg::ShowPowderDlg() +{ + if(!m_pPowderDlg) + m_pPowderDlg = new PowderDlg(this, &m_settings); + + m_pPowderDlg->show(); + m_pPowderDlg->activateWindow(); +} + +void TazDlg::ShowDispDlg() +{ + if(!m_pDispDlg) + m_pDispDlg = new DispDlg(this, &m_settings); + + m_pDispDlg->show(); + m_pDispDlg->activateWindow(); +} + +void TazDlg::ShowSettingsDlg() +{ + if(!m_pSettingsDlg) + m_pSettingsDlg = new SettingsDlg(this, &m_settings); + + m_pSettingsDlg->show(); + m_pSettingsDlg->activateWindow(); +} + +void TazDlg::ShowDWDlg() +{ + if(!m_pDWDlg) + m_pDWDlg = new DWDlg(this, &m_settings); + + m_pDWDlg->show(); + m_pDWDlg->activateWindow(); +} + +void TazDlg::ShowDynPlaneDlg() +{ + if(!m_pDynPlaneDlg) + { + m_pDynPlaneDlg = new DynPlaneDlg(this, &m_settings); + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + m_pDynPlaneDlg, SLOT(RecipParamsChanged(const RecipParams&))); + m_sceneRecip.emitAllParams(); + } + + m_pDynPlaneDlg->show(); + m_pDynPlaneDlg->activateWindow(); +} + +void TazDlg::UpdateDs() +{ + t_real dMonoD = editMonoD->text().toDouble(); + t_real dAnaD = editAnaD->text().toDouble(); + + m_sceneRecip.SetDs(dMonoD, dAnaD); + + ResoParams resoparams; + resoparams.bMonoDChanged = 1; + resoparams.bAnaDChanged = 1; + resoparams.dMonoD = dMonoD; + resoparams.dAnaD = dAnaD; + + if(m_pGotoDlg) + { + m_pGotoDlg->SetD(editMonoD->text().toDouble(), editAnaD->text().toDouble()); + m_pGotoDlg->CalcMonoAna(); + m_pGotoDlg->CalcSample(); + } + + emit ResoParamsChanged(resoparams); +} + +void TazDlg::UpdateSampleSense() +{ + const bool bSense = checkSenseS->isChecked(); + m_sceneRecip.SetSampleSense(bSense); + + if(m_pGotoDlg) + { + m_pGotoDlg->SetSampleSense(bSense); + m_pGotoDlg->CalcSample(); + } + + ResoParams params; + params.bSensesChanged[1] = 1; + params.bScatterSenses[1] = bSense; + emit ResoParamsChanged(params); + + m_sceneRecip.emitUpdate(); +} + +void TazDlg::UpdateMonoSense() +{ + const bool bSense = checkSenseM->isChecked(); + m_sceneRecip.SetMonoSense(bSense); + + if(m_pGotoDlg) + { + m_pGotoDlg->SetMonoSense(bSense); + m_pGotoDlg->CalcMonoAna(); + } + + ResoParams params; + params.bSensesChanged[0] = 1; + params.bScatterSenses[0] = bSense; + emit ResoParamsChanged(params); +} + +void TazDlg::UpdateAnaSense() +{ + const bool bSense = checkSenseA->isChecked(); + m_sceneRecip.SetAnaSense(bSense); + + if(m_pGotoDlg) + { + m_pGotoDlg->SetAnaSense(bSense); + m_pGotoDlg->CalcMonoAna(); + } + + ResoParams params; + params.bSensesChanged[2] = 1; + params.bScatterSenses[2] = bSense; + emit ResoParamsChanged(params); +} + + +void TazDlg::RecipNodeEvent(bool bStarted) +{ + //tl::log_info("recip node movement: ", bStarted); + // optimises reso dialog update policy + if(m_pReso) + m_pReso->SetUpdateOn(!bStarted, 1); +} + +void TazDlg::RealNodeEvent(bool bStarted) +{ + //tl::log_info("real node movement: ", bStarted); + // optimises reso dialog update policy + if(m_pReso) + m_pReso->SetUpdateOn(1, !bStarted); +} + +void TazDlg::TofNodeEvent(bool bStarted) +{ + //tl::log_info("tof node movement: ", bStarted); + // optimises reso dialog update policy + if(m_pReso) + m_pReso->SetUpdateOn(1, !bStarted); +} + + +void TazDlg::RecipProjChanged() +{ + LatticeProj proj = LatticeProj::PARALLEL; + if(m_pProjGnom->isChecked()) + proj = LatticeProj::GNOMONIC; + else if(m_pProjStereo->isChecked()) + proj = LatticeProj::STEREOGRAPHIC; + else if(m_pProjPara->isChecked()) + proj = LatticeProj::PARALLEL; + else if(m_pProjPersp->isChecked()) + proj = LatticeProj::PERSPECTIVE; + + if(m_sceneProjRecip.GetLattice()) + { + m_sceneProjRecip.GetLattice()->SetProjection(proj); + m_sceneProjRecip.GetLattice()->CalcPeaks(m_latticecommon, true); + } +} + + +#if !defined NO_3D +void TazDlg::Show3D() +{ + if(!m_pRecip3d) + { + m_pRecip3d = new Recip3DDlg(this, &m_settings); + + t_real dTol = s_dPlaneDistTolerance; + m_pRecip3d->SetPlaneDistTolerance(dTol); + } + + if(!m_pRecip3d->isVisible()) + m_pRecip3d->show(); + m_pRecip3d->activateWindow(); + + CalcPeaks(); +} +#else +void TazDlg::Show3D() {} +#endif + +void TazDlg::EnableSmallq(bool bEnable) +{ + m_sceneRecip.GetTriangle()->SetqVisible(bEnable); +} + +void TazDlg::EnableBZ(bool bEnable) +{ + m_sceneRecip.GetTriangle()->SetBZVisible(bEnable); +} + +void TazDlg::EnableWS(bool bEnable) +{ + m_sceneRealLattice.GetLattice()->SetWSVisible(bEnable); +} + +void TazDlg::ShowEwaldSphere() +{ + EwaldSphere iEw = EWALD_NONE; + if(m_pEwaldSphereNone->isChecked()) + iEw = EWALD_NONE; + else if(m_pEwaldSphereKi->isChecked()) + iEw = EWALD_KI; + else if(m_pEwaldSphereKf->isChecked()) + iEw = EWALD_KF; + m_sceneRecip.GetTriangle()->SetEwaldSphereVisible(iEw); +} + +void TazDlg::EnableRealQDir(bool bEnable) +{ + m_sceneReal.GetTasLayout()->SetRealQVisible(bEnable); + m_sceneTof.GetTofLayout()->SetRealQVisible(bEnable); +} + +// Q position +void TazDlg::recipParamsChanged(const RecipParams& params) +{ + t_real dQx = -params.Q_rlu[0], dQy = -params.Q_rlu[1], dQz = -params.Q_rlu[2]; + t_real dE = params.dE; + + tl::set_eps_0(dQx); tl::set_eps_0(dQy); tl::set_eps_0(dQz); + tl::set_eps_0(dE); + + std::ostringstream ostrPos; + ostrPos.precision(g_iPrecGfx); + ostrPos << "Q = (" << dQx << ", " << dQy << ", " << dQz << ") rlu"; + ostrPos << ", E = " << dE << " meV"; + + ostrPos << ", BZ: (" + << params.G_rlu_accurate[0] << ", " + << params.G_rlu_accurate[1] << ", " + << params.G_rlu_accurate[2] << ")"; + + m_pCoordQStatusMsg->setText(ostrPos.str().c_str()); +} + +// cursor position +void TazDlg::RecipCoordsChanged(t_real dh, t_real dk, t_real dl, + bool bHasNearest, t_real dNearestH, t_real dNearestK, t_real dNearestL) +{ + tl::set_eps_0(dh); tl::set_eps_0(dk); tl::set_eps_0(dl); + tl::set_eps_0(dNearestH); tl::set_eps_0(dNearestK); tl::set_eps_0(dNearestL); + + std::ostringstream ostrPos; + ostrPos.precision(g_iPrecGfx); + ostrPos << "Cur: (" << dh << ", " << dk << ", " << dl << ") rlu"; + if(bHasNearest) + ostrPos << ", BZ: (" + << dNearestH << ", " << dNearestK << ", " << dNearestL << ")"; + + m_pCoordCursorStatusMsg->setText(ostrPos.str().c_str()); +} + +// cursor position +void TazDlg::RealCoordsChanged(t_real dh, t_real dk, t_real dl, + bool bHasNearest, t_real dNearestH, t_real dNearestK, t_real dNearestL) +{ + tl::set_eps_0(dh); tl::set_eps_0(dk); tl::set_eps_0(dl); + tl::set_eps_0(dNearestH); tl::set_eps_0(dNearestK); tl::set_eps_0(dNearestL); + + std::ostringstream ostrPos; + ostrPos.precision(g_iPrecGfx); + ostrPos << "Cur: (" << dh << ", " << dk << ", " << dl << ") frac"; + if(bHasNearest) + ostrPos << ", WS: (" + << dNearestH << ", " << dNearestK << ", " << dNearestL << ")"; + + m_pCoordCursorStatusMsg->setText(ostrPos.str().c_str()); +} + + + +//-------------------------------------------------------------------------------- +// parameter dialogs + +void TazDlg::ShowRecipParams() +{ + m_dlgRecipParam.show(); + m_dlgRecipParam.activateWindow(); +} + +void TazDlg::ShowRealParams() +{ + m_dlgRealParam.show(); + m_dlgRealParam.activateWindow(); +} + + + + +//-------------------------------------------------------------------------------- +// context menus + +void TazDlg::RecipContextMenu(const QPoint& _pt) +{ + if(!m_pviewRecip) return; + + QPoint pt = this->m_pviewRecip->mapToGlobal(_pt); + m_pMenuViewRecip->exec(pt); +} + +void TazDlg::RealContextMenu(const QPoint& _pt) +{ + if(!m_pviewReal) return; + + QPoint pt = this->m_pviewReal->mapToGlobal(_pt); + m_pMenuViewReal->exec(pt); +} + + +//-------------------------------------------------------------------------------- +// about & help dialogs + +void TazDlg::ShowAbout() +{ + if(!m_pAboutDlg) + m_pAboutDlg = new AboutDlg(this, &m_settings); + + m_pAboutDlg->show(); + m_pAboutDlg->activateWindow(); +} + +void TazDlg::ShowHelp() +{ + std::string strHelpProg = "assistant"; + std::string strHelpProgVer = strHelpProg + "-qt" + tl::var_to_str(QT_VER); + + std::string strHelp = find_resource("res/takin.qhc"); + if(strHelp == "") + { + QMessageBox::critical(this, "Error", "Help file could not be found."); + return; + } + + if(std::system((strHelpProgVer + " -collectionFile " + strHelp + "&").c_str()) == 0) + return; + if(std::system((strHelpProg + " -collectionFile " + strHelp + "&").c_str()) == 0) + return; + + tl::log_warn("Help viewer not found, trying associated application."); + + + // try opening html files directly + std::string strHelpHtml = find_resource("doc/index_help.html"); + std::string strFile = "file:///" + fs::absolute(strHelpHtml).string(); + if(QDesktopServices::openUrl(QUrl(strFile.c_str()))) + return; + + QMessageBox::critical(this, "Error", "Help viewer could not be started."); +} + +#include "taz.moc" diff --git a/tools/taz/taz.h b/tools/taz/taz.h new file mode 100644 index 0000000..81cb7ba --- /dev/null +++ b/tools/taz/taz.h @@ -0,0 +1,305 @@ +/** + * TAS tool + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#ifndef __TAZ_H__ +#define __TAZ_H__ + +#if !defined NO_NET + #include "dialogs/SrvDlg.h" + #include "dialogs/NetCacheDlg.h" + #include "nicos.h" + #include "sics.h" +#endif + +//#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ui/ui_taz.h" +#include "scattering_triangle.h" +#include "real_lattice.h" +#include "proj_lattice.h" +#include "tas_layout.h" +#include "tof_layout.h" + +#include "dialogs/RecipParamDlg.h" +#include "dialogs/RealParamDlg.h" +#include "dialogs/EllipseDlg.h" +#include "tools/res/ResoDlg.h" +#include "tools/monteconvo/ConvoDlg.h" +#include "tools/scanviewer/scanviewer.h" +#include "dialogs/SpurionDlg.h" +#include "dialogs/NeutronDlg.h" +#include "dialogs/GotoDlg.h" +#include "dialogs/PowderDlg.h" +#include "dialogs/DispDlg.h" +#include "dialogs/SettingsDlg.h" +#include "dialogs/DWDlg.h" +#include "dialogs/DynPlaneDlg.h" +#include "dialogs/FormfactorDlg.h" +#include "dialogs/AtomsDlg.h" +#include "dialogs/AboutDlg.h" + +#if !defined NO_3D + #include "recip3d.h" + #include "dialogs/EllipseDlg3D.h" +#endif + +#include "tools/sglist/SgListDlg.h" +#include "libs/spacegroups/spacegroup.h" +#include "libs/spacegroups/latticehelper.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" +#include "tlibs/math/lattice.h" + + +class TazDlg : public QMainWindow, Ui::TazDlg +{ Q_OBJECT + private: + void DeleteDialogs(); + + private: + bool m_bUpdateRecipEdits = 1; + + QAction *m_pSmallq = nullptr, *m_pSnapSmallq = nullptr; + QAction *m_pGoto = nullptr; + QAction *m_pBZ = nullptr, *m_pWS = nullptr; + QAction *m_pEwaldSphereNone = nullptr, + *m_pEwaldSphereKi = nullptr, *m_pEwaldSphereKf = nullptr; + QAction *m_pShowRealQDir = nullptr; + QAction *m_pProjGnom = nullptr, *m_pProjStereo = nullptr, + *m_pProjPara = nullptr, *m_pProjPersp = nullptr; + + std::vector m_vecEdits_real; + std::vector m_vecEdits_recip; + std::vector m_vecEdits_plane; + std::vector m_vecEdits_monoana; + + //std::vector m_vecSpinBoxesSample; + std::vector m_vecCheckBoxesSenses; + + std::vector m_vecEditNames_real; + std::vector m_vecEditNames_recip; + std::vector m_vecEditNames_plane; + std::vector m_vecEditNames_monoana; + + std::vector m_vecSpinBoxNamesSample; + std::vector m_vecCheckBoxNamesSenses; + + protected: + static constexpr t_real_glob s_dPlaneDistTolerance = + tl::get_plane_dist_tolerance(); + + bool m_bReady = false; + QSettings m_settings; + SettingsDlg *m_pSettingsDlg = nullptr; + + QLabel* m_pStatusMsg = nullptr; + QLabel* m_pCoordQStatusMsg = nullptr; + QLabel* m_pCoordCursorStatusMsg = nullptr; + + QMenu *m_pMenuViewRecip = nullptr; + QMenu *m_pMenuViewReal = nullptr; + + QSignalMapper *m_pMapperRecent = nullptr; + QSignalMapper *m_pMapperRecentImport = nullptr; + QMenu *m_pMenuRecent = nullptr; + QMenu *m_pMenuRecentImport = nullptr; + + // reciprocal lattice + LatticeCommon m_latticecommon; + ScatteringTriangleView *m_pviewRecip = nullptr; + ScatteringTriangleScene m_sceneRecip; + ProjLatticeView *m_pviewProjRecip = nullptr; + ProjLatticeScene m_sceneProjRecip; + + // real lattice + TasLayoutView *m_pviewReal = nullptr; + TasLayoutScene m_sceneReal; + TofLayoutView *m_pviewTof = nullptr; + TofLayoutScene m_sceneTof; + LatticeView *m_pviewRealLattice = nullptr; + LatticeScene m_sceneRealLattice; + + std::string m_strCurFile; + static const std::string s_strTitle; + + std::vector> m_vecAtoms; + CrystalSystem m_crystalsys = CRYS_NOT_SET; + + RecipParamDlg m_dlgRecipParam; + RealParamDlg m_dlgRealParam; + + ResoDlg *m_pReso = nullptr; + EllipseDlg *m_pEllipseDlg = nullptr; + ConvoDlg *m_pConvoDlg = nullptr; + + SpurionDlg *m_pSpuri = nullptr; + NeutronDlg *m_pNeutronDlg = nullptr; + GotoDlg *m_pGotoDlg = nullptr; + PowderDlg *m_pPowderDlg = nullptr; + DispDlg *m_pDispDlg = nullptr; + DWDlg *m_pDWDlg = nullptr; + DynPlaneDlg* m_pDynPlaneDlg = nullptr; + FormfactorDlg* m_pFormfactorDlg = nullptr; + AtomsDlg *m_pAtomsDlg = nullptr; + AboutDlg *m_pAboutDlg = nullptr; + + ScanViewerDlg *m_pScanViewer = nullptr; + +#if !defined NO_NET + SrvDlg *m_pSrvDlg = nullptr; + NetCache *m_pNetCache = nullptr; + NetCacheDlg *m_pNetCacheDlg = nullptr; +#endif + +#if !defined NO_3D + Recip3DDlg *m_pRecip3d = nullptr; + EllipseDlg3D *m_pEllipseDlg3D = nullptr; +#endif + + SgListDlg *m_pSgListDlg = nullptr; + + protected: + void InitReso(); + void InitGoto(); + + void RotatePlane(unsigned iAxis, t_real_glob dAngle); + + virtual void showEvent(QShowEvent *pEvt) override; + virtual void closeEvent(QCloseEvent* pEvt) override; + + virtual void dragEnterEvent(QDragEnterEvent *pEvt) override; + virtual void dropEvent(QDropEvent *pEvt) override; + + virtual void keyPressEvent(QKeyEvent *pEvt) override; + virtual void keyReleaseEvent(QKeyEvent *pEvt) override; + + public: + TazDlg(QWidget *pParent); + TazDlg() : TazDlg(0) { } + virtual ~TazDlg(); + + bool Load(const char* pcFile); + bool Import(const char* pcFile); + + protected slots: + void CalcPeaks(); + void CalcPeaksRecip(); + void UpdateDs(); + + void SetCrystalType(); + void CheckCrystalType(); + + void UpdateSampleSense(); + void UpdateMonoSense(); + void UpdateAnaSense(); + void EnableSmallq(bool bEnable); + void EnableBZ(bool bEnable); + void EnableWS(bool bEnable); + void EnableRealQDir(bool bEnable); + void ShowEwaldSphere(); + void RecipProjChanged(); + + void RecipContextMenu(const QPoint&); + void RealContextMenu(const QPoint&); + + void ShowHelp(); + void ShowAbout(); + + void New(); + bool Save(); + bool SaveAs(); + bool Load(); + bool Import(); + + void ShowScanViewer(); + + bool LoadFile(const QString& strFile); + bool ImportFile(const QString& strFile); + + void ExportReal(); + void ExportTof(); + void ExportRealLattice(); + void ExportRecip(); + void ExportProj(); + void ExportBZImage(); + void ExportWSImage(); + void ExportUCModel(); + + void RepopulateSpaceGroups(); + + void ShowRecipParams(); + void ShowRealParams(); + + void ShowResoParams(); + void ShowResoEllipses(); + void ShowResoConv(); + + void ShowNeutronDlg(); + void ShowGotoDlg(); + void ShowPowderDlg(); + void ShowDispDlg(); + void ShowSettingsDlg(); + void ShowDWDlg(); + void ShowDynPlaneDlg(); + + void Show3D(); + void ShowResoEllipses3D(); + + void ShowSgListDlg(); + void ShowFormfactorDlg(); + + void ShowAtomsDlg(); + void ApplyAtoms(const std::vector>& vecAtoms); + + + void ShowSpurions(); + void spurionInfo(const tl::ElasticSpurion& spuris, + const std::vector>& vecInelCKI, + const std::vector>& vecInelCKF); + void recipParamsChanged(const RecipParams&); + + void ShowConnectDlg(); + + void ConnectTo(int iSys, const QString& strHost, const QString& strPort, + const QString& strUser, const QString& strPass); + void Disconnect(); + void NetRefresh(); + void ShowNetCache(); + + void Connected(const QString& strHost, const QString& strSrv); + void Disconnected(); + void VarsChanged(const CrystalOptions& crys, const TriangleOptions& triag); + + void RecipCoordsChanged(t_real_glob dh, t_real_glob dk, t_real_glob dl, + bool bHasNearest, t_real_glob dNearestH, t_real_glob dNearestK, t_real_glob dNearestL); + void RealCoordsChanged(t_real_glob dh, t_real_glob dk, t_real_glob dl, + bool bHasNearest, t_real_glob dNearestH, t_real_glob dNearestK, t_real_glob dNearestL); + + void SettingsChanged(); + + void RecipNodeEvent(bool bStarted); + void RealNodeEvent(bool bStarted); + void TofNodeEvent(bool bStarted); + + protected: + void ExportSceneSVG(QGraphicsScene& scene); + void emitSampleParams(); + + signals: + void ResoParamsChanged(const ResoParams& resoparams); + void SampleParamsChanged(const SampleParams& parms); +}; + +#endif diff --git a/tools/taz/taz_crys.cpp b/tools/taz/taz_crys.cpp new file mode 100644 index 0000000..e7c70aa --- /dev/null +++ b/tools/taz/taz_crys.cpp @@ -0,0 +1,613 @@ +/** + * TAS tool (crystal stuff) + * @author tweber + * @date 2014 - 2016 + * @license GPLv2 + */ + +#include "taz.h" +#include "tlibs/string/string.h" +#include "tlibs/string/spec_char.h" +#include + + +using t_real = t_real_glob; + +static inline QString dtoqstr(t_real dVal, unsigned int iPrec=8) +{ + std::string str = tl::var_to_str(dVal, iPrec); + return QString(str.c_str()); +} + +std::ostream& operator<<(std::ostream& ostr, const tl::Lattice& lat) +{ + ostr << "a = " << lat.GetA(); + ostr << ", b = " << lat.GetB(); + ostr << ", c = " << lat.GetC(); + ostr << ", alpha = " << lat.GetAlpha(); + ostr << ", beta = " << lat.GetBeta(); + ostr << ", gamma = " << lat.GetGamma(); + return ostr; +} + +void TazDlg::emitSampleParams() +{ + t_real a = editA->text().toDouble(); + t_real b = editB->text().toDouble(); + t_real c = editC->text().toDouble(); + + t_real alpha = tl::d2r(editAlpha->text().toDouble()); + t_real beta = tl::d2r(editBeta->text().toDouble()); + t_real gamma = tl::d2r(editGamma->text().toDouble()); + + t_real dX0 = editScatX0->text().toDouble(); + t_real dX1 = editScatX1->text().toDouble(); + t_real dX2 = editScatX2->text().toDouble(); + + t_real dY0 = editScatY0->text().toDouble(); + t_real dY1 = editScatY1->text().toDouble(); + t_real dY2 = editScatY2->text().toDouble(); + + SampleParams sampleparams; + sampleparams.dAngles[0] = alpha; sampleparams.dAngles[1] = beta; sampleparams.dAngles[2] = gamma; + sampleparams.dLattice[0] = a; sampleparams.dLattice[1] = b; sampleparams.dLattice[2] = c; + sampleparams.dPlane1[0] = dX0; sampleparams.dPlane1[1] = dX1; sampleparams.dPlane1[2] = dX2; + sampleparams.dPlane2[0] = dY0; sampleparams.dPlane2[1] = dY1; sampleparams.dPlane2[2] = dY2; + emit SampleParamsChanged(sampleparams); +} + +void TazDlg::SetCrystalType() +{ + m_crystalsys = CrystalSystem::CRYS_NOT_SET; + + SpaceGroup *pSpaceGroup = 0; + int iSpaceGroupIdx = comboSpaceGroups->currentIndex(); + if(iSpaceGroupIdx != 0) + pSpaceGroup = (SpaceGroup*)comboSpaceGroups->itemData(iSpaceGroupIdx).value(); + if(pSpaceGroup) + m_crystalsys = pSpaceGroup->GetCrystalSystem(); + + CheckCrystalType(); +} + +void TazDlg::CheckCrystalType() +{ + set_crystal_system_edits(m_crystalsys, editA, editB, editC, + editAlpha, editBeta, editGamma, + editARecip, editBRecip, editCRecip, + editAlphaRecip, editBetaRecip, editGammaRecip); +} + +void TazDlg::CalcPeaksRecip() +{ + if(!m_bReady) return; + + try + { + t_real a = editARecip->text().toDouble(); + t_real b = editBRecip->text().toDouble(); + t_real c = editCRecip->text().toDouble(); + + t_real alpha = tl::d2r(editAlphaRecip->text().toDouble()); + t_real beta = tl::d2r(editBetaRecip->text().toDouble()); + t_real gamma = tl::d2r(editGammaRecip->text().toDouble()); + + tl::Lattice lattice(a,b,c, alpha,beta,gamma); + tl::Lattice recip = lattice.GetRecip(); + + editA->setText(dtoqstr(recip.GetA(), g_iPrec)); + editB->setText(dtoqstr(recip.GetB(), g_iPrec)); + editC->setText(dtoqstr(recip.GetC(), g_iPrec)); + editAlpha->setText(dtoqstr(tl::r2d(recip.GetAlpha()), g_iPrec)); + editBeta->setText(dtoqstr(tl::r2d(recip.GetBeta()), g_iPrec)); + editGamma->setText(dtoqstr(tl::r2d(recip.GetGamma()), g_iPrec)); + + m_bUpdateRecipEdits = 0; + CalcPeaks(); + m_bUpdateRecipEdits = 1; + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + } +} + +void TazDlg::CalcPeaks() +{ + if(!m_bReady || !m_sceneRecip.GetTriangle() || !m_sceneRealLattice.GetLattice()) + return; + + try + { + const bool bPowder = checkPowder->isChecked(); + + // lattice + const t_real a = editA->text().toDouble(); + const t_real b = editB->text().toDouble(); + const t_real c = editC->text().toDouble(); + + const t_real alpha = tl::d2r(editAlpha->text().toDouble()); + const t_real beta = tl::d2r(editBeta->text().toDouble()); + const t_real gamma = tl::d2r(editGamma->text().toDouble()); +#ifndef NDEBUG + tl::log_debug("lattice consts = ", a, ", ", b, ", ", c); + tl::log_debug("lattice angles = ", alpha, ", ", beta, ", ", gamma); +#endif + + tl::Lattice lattice(a,b,c, alpha,beta,gamma); + tl::Lattice recip_unrot = lattice.GetRecip(); + + + //---------------------------------------------------------------------- + // scattering plane + t_real dX0 = editScatX0->text().toDouble(); + t_real dX1 = editScatX1->text().toDouble(); + t_real dX2 = editScatX2->text().toDouble(); + ublas::vector vecPlaneXRLU = tl::make_vec({dX0, dX1, dX2}); + + t_real dY0 = editScatY0->text().toDouble(); + t_real dY1 = editScatY1->text().toDouble(); + t_real dY2 = editScatY2->text().toDouble(); + ublas::vector vecPlaneYRLU = tl::make_vec({dY0, dY1, dY2}); + + //---------------------------------------------------------------------- + // show integer up vector + unsigned int iMaxDec = 4; // TODO: determine max. # of entered decimals + ublas::vector ivecUp = tl::cross_3( + tl::make_vec>({int(dX0*std::pow(10, iMaxDec)), + int(dX1*std::pow(10, iMaxDec)), + int(dX2*std::pow(10, iMaxDec))}), + tl::make_vec>({int(dY0*std::pow(10, iMaxDec)), + int(dY1*std::pow(10, iMaxDec)), + int(dY2*std::pow(10, iMaxDec))})); + ivecUp = tl::get_gcd_vec(ivecUp); + editScatZ0->setText(tl::var_to_str(ivecUp[0], g_iPrec).c_str()); + editScatZ1->setText(tl::var_to_str(ivecUp[1], g_iPrec).c_str()); + editScatZ2->setText(tl::var_to_str(ivecUp[2], g_iPrec).c_str()); + //---------------------------------------------------------------------- + + ublas::vector vecX0 = ublas::zero_vector(3); + tl::Plane planeRLU(vecX0, vecPlaneXRLU, vecPlaneYRLU); + if(!planeRLU.IsValid()) + { + tl::log_err("Invalid scattering plane."); + return; + } + //---------------------------------------------------------------------- + + + //---------------------------------------------------------------------- + // view plane for real lattice + // scattering plane + t_real dX0R = editRealX0->text().toDouble(); + t_real dX1R = editRealX1->text().toDouble(); + t_real dX2R = editRealX2->text().toDouble(); + ublas::vector vecPlaneXR = tl::make_vec({dX0R, dX1R, dX2R}); + + t_real dY0R = editRealY0->text().toDouble(); + t_real dY1R = editRealY1->text().toDouble(); + t_real dY2R = editRealY2->text().toDouble(); + ublas::vector vecPlaneYR = tl::make_vec({dY0R, dY1R, dY2R}); + + //---------------------------------------------------------------------- + // show integer up vector + unsigned int iMaxDecR = 4; // TODO: determine max. # of entered decimals + ublas::vector ivecUpR = tl::cross_3( + tl::make_vec>({int(dX0R*std::pow(10, iMaxDecR)), + int(dX1R*std::pow(10, iMaxDecR)), + int(dX2R*std::pow(10, iMaxDecR))}), + tl::make_vec>({int(dY0R*std::pow(10, iMaxDecR)), + int(dY1R*std::pow(10, iMaxDecR)), + int(dY2R*std::pow(10, iMaxDecR))})); + ivecUpR = tl::get_gcd_vec(ivecUpR); + editRealZ0->setText(tl::var_to_str(ivecUpR[0], g_iPrec).c_str()); + editRealZ1->setText(tl::var_to_str(ivecUpR[1], g_iPrec).c_str()); + editRealZ2->setText(tl::var_to_str(ivecUpR[2], g_iPrec).c_str()); + //---------------------------------------------------------------------- + + ublas::vector vecX0R = ublas::zero_vector(3); + tl::Plane planeRealFrac(vecX0R, vecPlaneXR, vecPlaneYR); + if(!planeRealFrac.IsValid()) + { + tl::log_err("Invalid view plane for real lattice."); + return; + } + //---------------------------------------------------------------------- + + + /* + // rotated lattice + t_real dPhi = spinRotPhi->value() / 180. * M_PI; + t_real dTheta = spinRotTheta->value() / 180. * M_PI; + t_real dPsi = spinRotPsi->value() / 180. * M_PI; + //lattice.RotateEuler(dPhi, dTheta, dPsi); + + ublas::vector dir0 = plane.GetDir0(); + ublas::vector dirup = plane.GetNorm(); + ublas::vector dir1 = tl::cross_3(dirup, dir0); + + t_real dDir0Len = ublas::norm_2(dir0); + t_real dDir1Len = ublas::norm_2(dir1); + t_real dDirUpLen = ublas::norm_2(dirup); + + if(tl::float_equal(dDir0Len, 0.) || tl::float_equal(dDir1Len, 0.) || tl::float_equal(dDirUpLen, 0.) + || tl::is_nan_or_inf(dDir0Len) || tl::is_nan_or_inf(dDir1Len) || tl::is_nan_or_inf(dDirUpLen)) + { + tl::log_err("Invalid scattering plane."); + return; + } + + dir0 /= dDir0Len; + dir1 /= dDir1Len; + //dirup /= dDirUpLen; + */ + + if(m_pGotoDlg) + { + m_pGotoDlg->SetLattice(lattice); + m_pGotoDlg->SetScatteringPlane(tl::make_vec({dX0, dX1, dX2}), tl::make_vec({dY0, dY1, dY2})); + m_pGotoDlg->CalcSample(); + } + + emitSampleParams(); + + //lattice.RotateEulerRecip(dir0, dir1, dirup, dPhi, dTheta, dPsi); + //tl::Lattice recip = lattice.GetRecip(); + const tl::Lattice& recip = recip_unrot; // anyway not rotated anymore + + + if(m_bUpdateRecipEdits) + { + editARecip->setText(dtoqstr(recip.GetA(), g_iPrec)); + editBRecip->setText(dtoqstr(recip.GetB(), g_iPrec)); + editCRecip->setText(dtoqstr(recip.GetC(), g_iPrec)); + editAlphaRecip->setText(dtoqstr(tl::r2d(recip.GetAlpha()), g_iPrec)); + editBetaRecip->setText(dtoqstr(tl::r2d(recip.GetBeta()), g_iPrec)); + editGammaRecip->setText(dtoqstr(tl::r2d(recip.GetGamma()), g_iPrec)); + } + + const std::wstring& strAA = tl::get_spec_char_utf16("AA"); + const std::wstring& strMinus = tl::get_spec_char_utf16("sup-"); + const std::wstring& strThree = tl::get_spec_char_utf16("sup3"); + + t_real dVol = lattice.GetVol(); + t_real dVol_recip = recip.GetVol() /*/ (2.*M_PI*2.*M_PI*2.*M_PI)*/; + + std::wostringstream ostrSample; + ostrSample.precision(g_iPrecGfx); + ostrSample << "Unit Cell Volume: "; + ostrSample << "Real: " << dVol << " " << strAA << strThree; + ostrSample << ", Recip.: " << dVol_recip << " " << strAA << strMinus << strThree; + //tl::log_info(tl::wstr_to_str(ostrSample.str())); + m_pStatusMsg->setText(QString::fromWCharArray(ostrSample.str().c_str())); + + + std::string strCryTy = ""; + SpaceGroup* pSpaceGroup = nullptr; + int iSpaceGroupIdx = comboSpaceGroups->currentIndex(); + if(iSpaceGroupIdx != 0) + pSpaceGroup = (SpaceGroup*)comboSpaceGroups->itemData(iSpaceGroupIdx).value(); + + if(pSpaceGroup) + strCryTy = pSpaceGroup->GetCrystalSystemName(); + + editCrystalSystem->setText(strCryTy.c_str()); + + + m_latticecommon = LatticeCommon(); + if(m_latticecommon.Calc(lattice, recip, planeRLU, planeRealFrac, pSpaceGroup, &m_vecAtoms)) + { + m_sceneRecip.GetTriangle()->CalcPeaks(m_latticecommon, bPowder); + if(m_sceneRecip.getSnapq()) + m_sceneRecip.GetTriangle()->SnapToNearestPeak(m_sceneRecip.GetTriangle()->GetNodeGq()); + m_sceneRecip.emitUpdate(); + + m_sceneProjRecip.GetLattice()->CalcPeaks(m_latticecommon, true); + + m_sceneRealLattice.GetLattice()->CalcPeaks(m_latticecommon); +#ifndef NO_3D + if(m_pRecip3d) + m_pRecip3d->CalcPeaks(m_latticecommon); +#endif + } + else + { + tl::log_err("Lattice calculations failed."); + } + + m_dlgRealParam.CrystalChanged(lattice, recip, pSpaceGroup, &m_vecAtoms); + } + catch(const std::exception& ex) + { + m_sceneRecip.GetTriangle()->ClearPeaks(); + tl::log_err(ex.what()); + } +} + +void TazDlg::RotatePlane(unsigned iAxis, t_real dAngle) +{ + m_bReady = false; + + t_real dX0 = editScatX0->text().toDouble(); + t_real dX1 = editScatX1->text().toDouble(); + t_real dX2 = editScatX2->text().toDouble(); + ublas::vector vecX = tl::make_vec({dX0, dX1, dX2}); + + t_real dY0 = editScatY0->text().toDouble(); + t_real dY1 = editScatY1->text().toDouble(); + t_real dY2 = editScatY2->text().toDouble(); + ublas::vector vecY = tl::make_vec({dY0, dY1, dY2}); + + ublas::vector vecZ = tl::cross_3(vecX, vecY); + + std::vector> vecOrth = + tl::gram_schmidt> + ({vecX, vecY, vecZ}, 1); + + ublas::matrix matRot = + tl::rotation_matrix(vecOrth[iAxis], dAngle); + vecX = ublas::prod(matRot, vecOrth[0]); + vecY = ublas::prod(matRot, vecOrth[1]); + + tl::set_eps_0(vecX, g_dEps); + tl::set_eps_0(vecY, g_dEps); + + editScatX0->setText(tl::var_to_str(vecX[0], g_iPrec).c_str()); + editScatX1->setText(tl::var_to_str(vecX[1], g_iPrec).c_str()); + editScatX2->setText(tl::var_to_str(vecX[2], g_iPrec).c_str()); + editScatY0->setText(tl::var_to_str(vecY[0], g_iPrec).c_str()); + editScatY1->setText(tl::var_to_str(vecY[1], g_iPrec).c_str()); + editScatY2->setText(tl::var_to_str(vecY[2], g_iPrec).c_str()); + + m_bReady = true; + CalcPeaks(); +} + +void TazDlg::RepopulateSpaceGroups() +{ + std::shared_ptr> sgs = SpaceGroups::GetInstance(); + const SpaceGroups::t_mapSpaceGroups* pmapSpaceGroups = sgs->get_space_groups(); + if(!pmapSpaceGroups) + return; + + QString strCurSG = comboSpaceGroups->currentText(); + comboSpaceGroups->setCurrentIndex(0); + + for(int iCnt=comboSpaceGroups->count()-1; iCnt>0; --iCnt) + comboSpaceGroups->removeItem(iCnt); + + std::string strFilter = editSpaceGroupsFilter->text().toStdString(); + + for(const SpaceGroups::t_mapSpaceGroups::value_type& pair : *pmapSpaceGroups) + { + const std::string& strName = pair.second.GetName(); + + typedef const boost::iterator_range t_striterrange; + if(strFilter!="" && + !boost::ifind_first(t_striterrange(strName.begin(), strName.end()), + t_striterrange(strFilter.begin(), strFilter.end()))) + continue; + + comboSpaceGroups->insertItem(comboSpaceGroups->count(), + strName.c_str(), QVariant::fromValue((void*)&pair.second)); + } + + + int iSGIdx = comboSpaceGroups->findText(strCurSG); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); +} + + +//-------------------------------------------------------------------------------- +// spurion stuff + +void TazDlg::ShowSpurions() +{ + if(!m_pSpuri) + { + m_pSpuri = new SpurionDlg(this, &m_settings); + + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + m_pSpuri, SLOT(paramsChanged(const RecipParams&))); + + m_sceneRecip.emitAllParams(); + } + + m_pSpuri->show(); + m_pSpuri->activateWindow(); +} + +void TazDlg::spurionInfo(const tl::ElasticSpurion& spuri, + const std::vector>& vecInelCKI, + const std::vector>& vecInelCKF) +{ + std::ostringstream ostrMsg; + if(spuri.bAType || spuri.bMType || vecInelCKI.size() || vecInelCKF.size()) + ostrMsg << "Warning: "; + + if(spuri.bAType || spuri.bMType) + { + ostrMsg << "Spurious elastic scattering of type "; + if(spuri.bAType && spuri.bMType) + { + ostrMsg << "A and M"; + ostrMsg << (spuri.bAKfSmallerKi ? " (kfki)"); + } + else if(spuri.bAType) + { + ostrMsg << "A"; + ostrMsg << (spuri.bAKfSmallerKi ? " (kfki)"); + } + else if(spuri.bMType) + { + ostrMsg << "M"; + ostrMsg << (spuri.bMKfSmallerKi ? " (kfki)"); + } + ostrMsg << "."; + + if(vecInelCKI.size() || vecInelCKF.size()) + ostrMsg << " "; + } + + const std::string& strDelta = tl::get_spec_char_utf8("Delta"); + + if(vecInelCKI.size()) + { + ostrMsg << "Spurious inelastic CKI scattering at " + << strDelta << "E = "; + for(unsigned int iInel=0; iInelsetText(QString::fromUtf8(ostrMsg.str().c_str(), ostrMsg.str().size())); +} + + + +//-------------------------------------------------------------------------------- +// reso stuff +void TazDlg::InitReso() +{ + if(!m_pReso) + { + m_pReso = new ResoDlg(this, &m_settings); + + QObject::connect(this, SIGNAL(ResoParamsChanged(const ResoParams&)), + m_pReso, SLOT(ResoParamsChanged(const ResoParams&))); + QObject::connect(&m_sceneRecip, SIGNAL(paramsChanged(const RecipParams&)), + m_pReso, SLOT(RecipParamsChanged(const RecipParams&))); + QObject::connect(&m_sceneReal, SIGNAL(paramsChanged(const RealParams&)), + m_pReso, SLOT(RealParamsChanged(const RealParams&))); + QObject::connect(this, SIGNAL(SampleParamsChanged(const SampleParams&)), + m_pReso, SLOT(SampleParamsChanged(const SampleParams&))); + + UpdateDs(); + UpdateMonoSense(); + UpdateSampleSense(); + UpdateAnaSense(); + + emitSampleParams(); + m_sceneRecip.emitAllParams(); + m_sceneReal.emitAllParams(); + } +} + +void TazDlg::ShowResoParams() +{ + InitReso(); + + m_pReso->show(); + m_pReso->activateWindow(); +} + +void TazDlg::ShowResoEllipses() +{ + InitReso(); + + if(!m_pEllipseDlg) + { + m_pEllipseDlg = new EllipseDlg(this, &m_settings); + QObject::connect(m_pReso, SIGNAL(ResoResultsSig(const EllipseDlgParams&)), + m_pEllipseDlg, SLOT(SetParams(const EllipseDlgParams&))); + + m_pReso->EmitResults(); + } + + m_pEllipseDlg->show(); + m_pEllipseDlg->activateWindow(); +} + +void TazDlg::ShowResoConv() +{ + if(!m_pConvoDlg) + m_pConvoDlg = new ConvoDlg(this, &m_settings); + + m_pConvoDlg->show(); + m_pConvoDlg->activateWindow(); +} + +#ifndef NO_3D +void TazDlg::ShowResoEllipses3D() +{ + InitReso(); + + if(!m_pEllipseDlg3D) + { + m_pEllipseDlg3D = new EllipseDlg3D(this, &m_settings); + QObject::connect(m_pReso, + SIGNAL(ResoResultsSig(const EllipseDlgParams&)), + m_pEllipseDlg3D, SLOT(SetParams(const EllipseDlgParams&))); + + m_pReso->EmitResults(); + } + + m_pEllipseDlg3D->show(); + m_pEllipseDlg3D->activateWindow(); +} + +#else +void TazDlg::ShowResoEllipses3D() {} +#endif + + + +//-------------------------------------------------------------------------------- +// spacegroups & formfactors dialogs + +void TazDlg::ShowFormfactorDlg() +{ + if(!m_pFormfactorDlg) + m_pFormfactorDlg = new FormfactorDlg(this, &m_settings); + m_pFormfactorDlg->show(); + m_pFormfactorDlg->activateWindow(); +} + +void TazDlg::ShowAtomsDlg() +{ + if(!m_pAtomsDlg) + { + m_pAtomsDlg = new AtomsDlg(this, &m_settings); + QObject::connect(m_pAtomsDlg, SIGNAL(ApplyAtoms(const std::vector>&)), + this, SLOT(ApplyAtoms(const std::vector>&))); + } + + m_pAtomsDlg->SetAtoms(m_vecAtoms); + m_pAtomsDlg->show(); + m_pAtomsDlg->activateWindow(); +} + +void TazDlg::ApplyAtoms(const std::vector>& vecAtoms) +{ + m_vecAtoms = vecAtoms; + CalcPeaks(); +} + +void TazDlg::ShowSgListDlg() +{ + if(!m_pSgListDlg) + m_pSgListDlg = new SgListDlg(this); + m_pSgListDlg->show(); + m_pSgListDlg->activateWindow(); +} diff --git a/tools/taz/taz_export.cpp b/tools/taz/taz_export.cpp new file mode 100644 index 0000000..8c3677b --- /dev/null +++ b/tools/taz/taz_export.cpp @@ -0,0 +1,291 @@ +/* + * exports + * @author tweber + * @date dec-2015 + * @license GPLv2 + */ + +#include "taz.h" +#include "tlibs/math/atoms.h" +#include "tlibs/file/x3d.h" +#include "tlibs/log/log.h" + +#include +#include +#include + + +using t_real = t_real_glob; + +//-------------------------------------------------------------------------------- +// image exports + +void TazDlg::ExportReal() +{ + TasLayout *pTas = m_sceneReal.GetTasLayout(); + if(!pTas) return; + + const t_real dZoom = pTas->GetZoom(); + pTas->SetZoom(1.); + ExportSceneSVG(m_sceneReal); + pTas->SetZoom(dZoom); +} + +void TazDlg::ExportTof() +{ + TofLayout *pTof = m_sceneTof.GetTofLayout(); + if(!pTof) return; + + const t_real dZoom = pTof->GetZoom(); + pTof->SetZoom(1.); + ExportSceneSVG(m_sceneTof); + pTof->SetZoom(dZoom); +} + +void TazDlg::ExportRealLattice() +{ + RealLattice *pLatt = m_sceneRealLattice.GetLattice(); + if(!pLatt) return; + + const t_real dZoom = pLatt->GetZoom(); + pLatt->SetZoom(1.); + ExportSceneSVG(m_sceneRealLattice); + pLatt->SetZoom(dZoom); +} + +void TazDlg::ExportRecip() +{ + ScatteringTriangle *pTri = m_sceneRecip.GetTriangle(); + if(!pTri) return; + + const t_real dZoom = pTri->GetZoom(); + pTri->SetZoom(1.); + ExportSceneSVG(m_sceneRecip); + pTri->SetZoom(dZoom); +} + +void TazDlg::ExportProj() +{ + ProjLattice *pLatt = m_sceneProjRecip.GetLattice(); + if(!pLatt) return; + + const t_real dZoom = pLatt->GetZoom(); + pLatt->SetZoom(1.); + ExportSceneSVG(m_sceneProjRecip); + pLatt->SetZoom(dZoom); +} + +void TazDlg::ExportSceneSVG(QGraphicsScene& scene) +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir_export", ".").toString(); + QString strFile = QFileDialog::getSaveFileName(this, + "Export SVG", strDirLast, "SVG files (*.svg *.SVG)", nullptr, fileopt); + if(strFile == "") + return; + + QRectF rect = scene.sceneRect(); + + QSvgGenerator svg; + svg.setFileName(strFile); + svg.setSize(QSize(rect.width(), rect.height())); + //svg.setResolution(300); + svg.setViewBox(QRectF(0, 0, rect.width(), rect.height())); + svg.setDescription("Created with Takin"); + + QPainter painter; + painter.begin(&svg); + scene.render(&painter); + painter.end(); + + std::string strDir = tl::get_dir(strFile.toStdString()); + m_settings.setValue("main/last_dir_export", QString(strDir.c_str())); +} + +#ifdef USE_GIL +void TazDlg::ExportBZImage() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir_export", ".").toString(); + QString strFile = QFileDialog::getSaveFileName(this, + "Export PNG", strDirLast, "PNG files (*.png *.PNG)", nullptr, fileopt); + if(strFile == "") + return; + + bool bOk = m_sceneRecip.ExportBZAccurate(strFile.toStdString().c_str()); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not export image."); + + if(bOk) + { + std::string strDir = tl::get_dir(strFile.toStdString()); + m_settings.setValue("main/last_dir_export", QString(strDir.c_str())); + } +} + +void TazDlg::ExportWSImage() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir_export", ".").toString(); + QString strFile = QFileDialog::getSaveFileName(this, + "Export PNG", strDirLast, "PNG files (*.png *.PNG)", nullptr, fileopt); + if(strFile == "") + return; + + bool bOk = m_sceneRealLattice.ExportWSAccurate(strFile.toStdString().c_str()); + if(!bOk) + QMessageBox::critical(this, "Error", "Could not export image."); + + if(bOk) + { + std::string strDir = tl::get_dir(strFile.toStdString()); + m_settings.setValue("main/last_dir_export", QString(strDir.c_str())); + } +} +#else +void TazDlg::ExportBZImage() {} +void TazDlg::ExportWSImage() {} +#endif + + + +//-------------------------------------------------------------------------------- +// 3d model exports + +void TazDlg::ExportUCModel() +{ + using t_mat = ublas::matrix; + using t_vec = ublas::vector; + + + if(m_vecAtoms.size() == 0) + { + QMessageBox::critical(this, "Error", "No atom positions defined for unit cell."); + return; + } + + + SpaceGroup* pSpaceGroup = nullptr; + int iSpaceGroupIdx = comboSpaceGroups->currentIndex(); + if(iSpaceGroupIdx != 0) + pSpaceGroup = (SpaceGroup*)comboSpaceGroups->itemData(iSpaceGroupIdx).value(); + if(!pSpaceGroup) + { + QMessageBox::critical(this, "Error", "Invalid space group."); + return; + } + + const std::vector& vecTrafos = pSpaceGroup->GetTrafos(); + + std::vector vecAtoms; + std::vector vecAtomNames; + for(const AtomPos& atom : m_vecAtoms) + { + t_vec vecAtomPos = atom.vecPos; + vecAtomPos.resize(4, 1); + vecAtomPos[3] = 1.; + vecAtoms.push_back(std::move(vecAtomPos)); + vecAtomNames.push_back(atom.strAtomName); + } + + + const t_real a = editA->text().toDouble(); + const t_real b = editB->text().toDouble(); + const t_real c = editC->text().toDouble(); + const t_real alpha = tl::d2r(editAlpha->text().toDouble()); + const t_real beta = tl::d2r(editBeta->text().toDouble()); + const t_real gamma = tl::d2r(editGamma->text().toDouble()); + const tl::Lattice lattice(a,b,c, alpha,beta,gamma); + const t_mat matA = lattice.GetMetric(); + + + const std::vector vecColors = + { + tl::make_vec({1., 0., 0.}), tl::make_vec({0., 1., 0.}), tl::make_vec({0., 0., 1.}), + tl::make_vec({1., 1., 0.}), tl::make_vec({0., 1., 1.}), tl::make_vec({1., 0., 1.}), + tl::make_vec({0.5, 0., 0.}), tl::make_vec({0., 0.5, 0.}), tl::make_vec({0., 0., 0.5}), + tl::make_vec({0.5, 0.5, 0.}), tl::make_vec({0., 0.5, 0.5}), tl::make_vec({0.5, 0., 0.5}), + tl::make_vec({1., 1., 1.}), tl::make_vec({0., 0., 0.}), tl::make_vec({0.5, 0.5, 0.5}), + }; + + // to transform into program-specific coordinate systems + const t_mat matGlobal = tl::make_mat( + { {-1., 0., 0., 0.}, + { 0., 0., 1., 0.}, + { 0., 1., 0., 0.}, + { 0., 0., 0., 1.} }); + + + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir_export", ".").toString(); + QString strFile = QFileDialog::getSaveFileName(this, + "Export X3D", strDirLast, "X3D files (*.x3d *.X3D)", nullptr, fileopt); + if(strFile == "") + return; + + + tl::X3d x3d; + std::ostringstream ostrComment; + + std::vector vecAllNames; + std::vector vecAllAtoms, vecAllAtomsFrac; + std::vector vecAllAtomTypes; + + const t_real dUCSize = 1.; + std::tie(vecAllNames, vecAllAtoms, vecAllAtomsFrac, vecAllAtomTypes) = + tl::generate_all_atoms + (vecTrafos, vecAtoms, + static_cast*>(0), matA, + -dUCSize*0.5, dUCSize*0.5, g_dEps); + + for(std::size_t iAtom=0; iAtomSetTrans(tl::mult(matGlobal, vecCoord)); + tl::X3dSphere *pSphere = new tl::X3dSphere(0.1); + pSphere->SetColor(vecColors[iAtomType % vecColors.size()]); + pTrafo->AddChild(pSphere); + + x3d.GetScene().AddChild(pTrafo); + + /*ostrComment << "Unit cell contains " << iGeneratedAtoms + << " " << strAtomName << " atoms (color: " + << vecColors[iAtomType % vecColors.size()] << ").\n";*/ + } + + // only for cubic unit cells! + //tl::X3dCube *pCube = new tl::X3dCube(a,b,c); + //pCube->SetColor(tl::make_vec({1., 1., 1., 0.75})); + //x3d.GetScene().AddChild(pCube); + + tl::log_info(ostrComment.str()); + x3d.SetComment(std::string("\nCreated with Takin.\n\n") + ostrComment.str()); + + bool bOk = x3d.Save(strFile.toStdString().c_str()); + + if(bOk) + { + std::string strDir = tl::get_dir(strFile.toStdString()); + m_settings.setValue("main/last_dir_export", QString(strDir.c_str())); + } + else + { + QMessageBox::critical(this, "Error", "Error exporting x3d file."); + } +} diff --git a/tools/taz/taz_file.cpp b/tools/taz/taz_file.cpp new file mode 100644 index 0000000..44c8d93 --- /dev/null +++ b/tools/taz/taz_file.cpp @@ -0,0 +1,653 @@ +/* + * TAS tool + * @author tweber + * @date feb-2015 + * @license GPLv2 + */ + +#include "taz.h" +#include "tlibs/string/string.h" +#include "dialogs/FilePreviewDlg.h" +#include "tlibs/file/recent.h" + +#include +#include +#include + + +//-------------------------------------------------------------------------------- +// loading/saving + +void TazDlg::New() +{ + CrystalOptions crys; + TriangleOptions triag; + + crys.dLattice[0] = crys.dLattice[1] = crys.dLattice[2] = 5.; + crys.dLatticeAngles[0] = crys.dLatticeAngles[1] = crys.dLatticeAngles[2] = 90.; + crys.bChangedLattice = crys.bChangedLatticeAngles = 1; + + crys.dPlane1[0] = 1.; crys.dPlane1[1] = 0.; crys.dPlane1[2] = 0.; + crys.dPlane2[0] = 0.; crys.dPlane2[1] = 1.; crys.dPlane2[2] = 0.; + crys.bChangedPlane1 = crys.bChangedPlane2 = 1; + + crys.strSampleName = " "; + crys.strSpacegroup = ""; + crys.bChangedSpacegroup = 1; + + triag.dAnaD = triag.dMonoD = 3.355; + triag.bChangedAnaD = triag.bChangedMonoD = 1; + triag.dAnaTwoTheta = triag.dMonoTwoTheta = tl::get_pi()/2.; + triag.bChangedAnaTwoTheta = triag.bChangedMonoTwoTheta = 1; + + triag.dTwoTheta = tl::get_pi()/2.; + triag.dAngleKiVec0 = tl::get_pi()/4.; + triag.bChangedTwoTheta = triag.bChangedAngleKiVec0 = 1; + + m_vecAtoms.clear(); + m_strCurFile = ""; + setWindowTitle(s_strTitle.c_str()); + + DeleteDialogs(); + Disconnect(); + VarsChanged(crys, triag); +} + +bool TazDlg::Load() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir", ".").toString(); + QString strFile = QFileDialog::getOpenFileName(this, + "Open TAS Configuration...", strDirLast, "Takin files (*.taz *.TAZ)", + nullptr, fileopt); + if(strFile == "") + return false; + + return Load(strFile.toStdString().c_str()); +} + +bool TazDlg::LoadFile(const QString& strFile) +{ + return Load(strFile.toStdString().c_str()); +} + +bool TazDlg::Load(const char* pcFile) +{ + m_bReady = 0; + BOOST_SCOPE_EXIT(&m_bReady, &m_sceneReal, &m_sceneRecip) + { + m_bReady = 1; + m_sceneReal.GetTasLayout()->SetReady(true); + m_sceneReal.SetEmitChanges(true); + + m_sceneRecip.GetTriangle()->SetReady(true); + m_sceneRecip.SetEmitChanges(true); + } BOOST_SCOPE_EXIT_END + + Disconnect(); + + const std::string strXmlRoot("taz/"); + + std::string strFile1 = pcFile; + std::string strDir = tl::get_dir(strFile1); + + + tl::Prop xml; + if(!xml.Load(strFile1.c_str(), tl::PropType::XML)) + { + std::string strErr = "Could not load file \"" + + std::string(pcFile) + "\"."; + QMessageBox::critical(this, "Error", strErr.c_str()); + return false; + } + + m_settings.setValue("main/last_dir", QString(strDir.c_str())); + + + bool bOk = 0; + m_sceneReal.SetEmitChanges(false); + m_sceneReal.GetTasLayout()->SetReady(false); + m_sceneRecip.SetEmitChanges(false); + m_sceneRecip.GetTriangle()->SetReady(false); + + + // edit boxes + std::vector*> vecEdits + = {&m_vecEdits_real, &m_vecEdits_recip, + &m_vecEdits_plane, &m_vecEdits_monoana}; + std::vector*> vecEditNames + = {&m_vecEditNames_real, &m_vecEditNames_recip, + &m_vecEditNames_plane, &m_vecEditNames_monoana}; + unsigned int iIdxEdit = 0; + for(const std::vector* pVec : vecEdits) + { + const std::vector* pvecName = vecEditNames[iIdxEdit]; + + for(unsigned int iEditBox=0; iEditBoxsize(); ++iEditBox) + { + std::string str = xml.Query((strXmlRoot+(*pvecName)[iEditBox]).c_str(), "0", &bOk); + tl::trim(str); + if(bOk) + (*pVec)[iEditBox]->setText(str.c_str()); + } + + ++iIdxEdit; + } + + std::string strDescr = xml.Query((strXmlRoot+"sample/descr").c_str(), "", &bOk); + if(bOk) + editDescr->setText(strDescr.c_str()); + + + /*// spin boxes + for(unsigned int iSpinBox=0; iSpinBox((strXmlRoot+m_vecSpinBoxNamesSample[iSpinBox]).c_str(), 0., &bOk); + if(bOk) + m_vecSpinBoxesSample[iSpinBox]->setValue(dVal); + }*/ + + + // check boxes + for(unsigned int iCheckBox=0; iCheckBox((strXmlRoot+m_vecCheckBoxNamesSenses[iCheckBox]).c_str(), 0, &bOk); + if(bOk) + m_vecCheckBoxesSenses[iCheckBox]->setChecked(iVal != 0); + } + + + // TAS Layout + double dRealScale = xml.Query((strXmlRoot + "real/pixels_per_cm").c_str(), 0., &bOk); + if(bOk) + m_sceneReal.GetTasLayout()->SetScaleFactor(dRealScale); + + unsigned int iNodeReal = 0; + for(TasLayoutNode *pNode : m_sceneReal.GetTasLayout()->GetNodes()) + { + std::string strNode = m_sceneReal.GetTasLayout()->GetNodeNames()[iNodeReal]; + + bool bOkX=0, bOkY=0; + double dValX = xml.Query((strXmlRoot + "real/" + strNode + "_x").c_str(), 0., &bOkX); + double dValY = xml.Query((strXmlRoot + "real/" + strNode + "_y").c_str(), 0., &bOkY); + + pNode->setPos(dValX, dValY); + ++iNodeReal; + } + + + + // scattering triangle + double dRecipScale = xml.Query((strXmlRoot + "recip/pixels_per_A-1").c_str(), 0., &bOk); + if(bOk) + m_sceneRecip.GetTriangle()->SetScaleFactor(dRecipScale); + + unsigned int iNodeRecip = 0; + for(ScatteringTriangleNode *pNode : m_sceneRecip.GetTriangle()->GetNodes()) + { + std::string strNode = m_sceneRecip.GetTriangle()->GetNodeNames()[iNodeRecip]; + + bool bOkX=0, bOkY=0; + double dValX = xml.Query((strXmlRoot + "recip/" + strNode + "_x").c_str(), 0., &bOkX); + double dValY = xml.Query((strXmlRoot + "recip/" + strNode + "_y").c_str(), 0., &bOkY); + + pNode->setPos(dValX, dValY); + ++iNodeRecip; + } + + + + int bSmallqEnabled = xml.Query((strXmlRoot + "recip/enable_q").c_str(), 0, &bOk); + if(bOk) + m_pSmallq->setChecked(bSmallqEnabled!=0); + + int bSmallqSnapped = xml.Query((strXmlRoot + "recip/snap_q").c_str(), 1, &bOk); + if(bOk) + m_pSnapSmallq->setChecked(bSmallqSnapped!=0); + + int bBZEnabled = xml.Query((strXmlRoot + "recip/enable_bz").c_str(), 0, &bOk); + if(bOk) + m_pBZ->setChecked(bBZEnabled!=0); + + int iEwald = xml.Query((strXmlRoot + "recip/ewald_sphere").c_str(), 0, &bOk); + if(bOk) + { + if(iEwald == EWALD_NONE) m_pEwaldSphereNone->setChecked(1); + else if(iEwald == EWALD_KI) m_pEwaldSphereKi->setChecked(1); + else if(iEwald == EWALD_KF) m_pEwaldSphereKf->setChecked(1); + } + + int bWSEnabled = xml.Query((strXmlRoot + "real/enable_ws").c_str(), 0, &bOk); + if(bOk) + m_pWS->setChecked(bWSEnabled!=0); + + int bRealQEnabled = xml.Query((strXmlRoot + "real/enable_realQDir").c_str(), 0, &bOk); + if(bOk) + m_pShowRealQDir->setChecked(bRealQEnabled!=0); + + std::string strSpaceGroup = xml.Query((strXmlRoot + "sample/spacegroup").c_str(), "", &bOk); + tl::trim(strSpaceGroup); + if(bOk) + { + editSpaceGroupsFilter->clear(); + int iSGIdx = comboSpaceGroups->findText(strSpaceGroup.c_str(), Qt::MatchFixedString); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); + else + comboSpaceGroups->setCurrentIndex(0); + } + + + m_vecAtoms.clear(); + unsigned int iNumAtoms = xml.Query((strXmlRoot + "sample/atoms/num").c_str(), 0, &bOk); + if(bOk) + { + m_vecAtoms.reserve(iNumAtoms); + + for(unsigned int iAtom=0; iAtom atom; + atom.vecPos.resize(3,0); + + std::string strNr = tl::var_to_str(iAtom); + atom.strAtomName = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/name").c_str(), ""); + atom.vecPos[0] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/x").c_str(), 0.); + atom.vecPos[1] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/y").c_str(), 0.); + atom.vecPos[2] = xml.Query((strXmlRoot + "sample/atoms/" + strNr + "/z").c_str(), 0.); + + m_vecAtoms.push_back(atom); + } + } + + + + if(xml.Exists((strXmlRoot + "reso").c_str())) + { + InitReso(); + m_pReso->Load(xml, strXmlRoot); + } + + if(m_pGotoDlg) + m_pGotoDlg->ClearList(); + + if(xml.Exists((strXmlRoot + "goto_favlist").c_str()) || + xml.Exists((strXmlRoot + "goto_pos").c_str())) + { + InitGoto(); + m_pGotoDlg->Load(xml, strXmlRoot); + } + + + m_strCurFile = strFile1; + setWindowTitle((s_strTitle + " - " + m_strCurFile).c_str()); + + tl::RecentFiles recent(&m_settings, "main/recent"); + recent.AddFile(strFile1.c_str()); + recent.SaveList(); + recent.FillMenu(m_pMenuRecent, m_pMapperRecent); + + + + m_bReady = 1; + + m_sceneReal.GetTasLayout()->SetReady(true); + m_sceneReal.SetEmitChanges(true); + //m_sceneReal.emitUpdate(); + + m_sceneRecip.GetTriangle()->SetReady(true); + m_sceneRecip.SetEmitChanges(true); + + CalcPeaks(); + m_sceneRecip.emitUpdate(); + + return true; +} + +bool TazDlg::Save() +{ + if(m_strCurFile == "") + return SaveAs(); + + const std::string strXmlRoot("taz/"); + typedef std::map tmap; + tmap mapConf; + + + // edit boxes + std::vector*> vecEdits + = {&m_vecEdits_real, &m_vecEdits_recip, + &m_vecEdits_plane, &m_vecEdits_monoana}; + std::vector*> vecEditNames + = {&m_vecEditNames_real, &m_vecEditNames_recip, + &m_vecEditNames_plane, &m_vecEditNames_monoana}; + unsigned int iIdxEdit = 0; + for(const std::vector* pVec : vecEdits) + { + const std::vector* pvecName = vecEditNames[iIdxEdit]; + + for(unsigned int iEditBox=0; iEditBoxsize(); ++iEditBox) + mapConf[strXmlRoot+(*pvecName)[iEditBox]] + = (*pVec)[iEditBox]->text().toStdString(); + + ++iIdxEdit; + } + + mapConf[strXmlRoot + "sample/descr"] = editDescr->text().toStdString(); + + /*// spin boxes + for(unsigned int iSpinBox=0; iSpinBoxvalue(); + + mapConf[strXmlRoot + m_vecSpinBoxNamesSample[iSpinBox]] = ostrVal.str(); + }*/ + + + // check boxes + for(unsigned int iCheckBox=0; iCheckBoxisChecked() ? "1" : "0"); + + + // TAS layout + unsigned int iNodeReal = 0; + for(const TasLayoutNode *pNode : m_sceneReal.GetTasLayout()->GetNodes()) + { + std::string strNode = m_sceneReal.GetTasLayout()->GetNodeNames()[iNodeReal]; + std::string strValX = tl::var_to_str(pNode->pos().x()); + std::string strValY = tl::var_to_str(pNode->pos().y()); + + mapConf[strXmlRoot + "real/" + strNode + "_x"] = strValX; + mapConf[strXmlRoot + "real/" + strNode + "_y"] = strValY; + + ++iNodeReal; + } + double dRealScale = m_sceneReal.GetTasLayout()->GetScaleFactor(); + mapConf[strXmlRoot + "real/pixels_per_cm"] = tl::var_to_str(dRealScale); + + + // scattering triangle + unsigned int iNodeRecip = 0; + for(const ScatteringTriangleNode *pNode : m_sceneRecip.GetTriangle()->GetNodes()) + { + std::string strNode = m_sceneRecip.GetTriangle()->GetNodeNames()[iNodeRecip]; + std::string strValX = tl::var_to_str(pNode->pos().x()); + std::string strValY = tl::var_to_str(pNode->pos().y()); + + mapConf[strXmlRoot + "recip/" + strNode + "_x"] = strValX; + mapConf[strXmlRoot + "recip/" + strNode + "_y"] = strValY; + + ++iNodeRecip; + } + double dRecipScale = m_sceneRecip.GetTriangle()->GetScaleFactor(); + mapConf[strXmlRoot + "recip/pixels_per_A-1"] = tl::var_to_str(dRecipScale); + + + bool bSmallqEnabled = m_pSmallq->isChecked(); + mapConf[strXmlRoot + "recip/enable_q"] = (bSmallqEnabled ? "1" : "0"); + + bool bSmallqSnapped = m_sceneRecip.getSnapq(); + mapConf[strXmlRoot + "recip/snap_q"] = (bSmallqSnapped ? "1" : "0"); + + bool bBZEnabled = m_pBZ->isChecked(); + mapConf[strXmlRoot + "recip/enable_bz"] = (bBZEnabled ? "1" : "0"); + + int iEw = EWALD_NONE; + if(m_pEwaldSphereKi->isChecked()) iEw = EWALD_KI; + else if(m_pEwaldSphereKf->isChecked()) iEw = EWALD_KF; + mapConf[strXmlRoot + "recip/ewald_sphere"] = tl::var_to_str(iEw); + + bool bWSEnabled = m_pWS->isChecked(); + mapConf[strXmlRoot + "real/enable_ws"] = (bWSEnabled ? "1" : "0"); + + bool bRealQDir = m_pShowRealQDir->isChecked(); + mapConf[strXmlRoot + "real/enable_realQDir"] = (bRealQDir ? "1" : "0"); + + + std::string strSG = comboSpaceGroups->currentText().toStdString(); + if(strSG == "") + strSG = "-1"; + mapConf[strXmlRoot + "sample/spacegroup"] = strSG; + + + mapConf[strXmlRoot + "sample/atoms/num"] = tl::var_to_str(m_vecAtoms.size()); + for(unsigned int iAtom=0; iAtom& atom = m_vecAtoms[iAtom]; + + std::string strAtomNr = tl::var_to_str(iAtom); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/name"] = + atom.strAtomName; + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/x"] = + tl::var_to_str(atom.vecPos[0]); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/y"] = + tl::var_to_str(atom.vecPos[1]); + mapConf[strXmlRoot + "sample/atoms/" + strAtomNr + "/z"] = + tl::var_to_str(atom.vecPos[2]); + } + + + if(m_pReso) m_pReso->Save(mapConf, strXmlRoot); + if(m_pGotoDlg) m_pGotoDlg->Save(mapConf, strXmlRoot); + + + tl::Prop xml; + xml.Add(mapConf); + if(!xml.Save(m_strCurFile.c_str(), tl::PropType::XML)) + { + QMessageBox::critical(this, "Error", "Could not save configuration file."); + return false; + } + + tl::RecentFiles recent(&m_settings, "main/recent"); + recent.AddFile(m_strCurFile.c_str()); + recent.SaveList(); + recent.FillMenu(m_pMenuRecent, m_pMapperRecent); + + return true; +} + +bool TazDlg::SaveAs() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + QString strDirLast = m_settings.value("main/last_dir", ".").toString(); + QString strFile = QFileDialog::getSaveFileName(this, + "Save TAS Configuration", strDirLast, "Takin files (*.taz *.TAZ)", + nullptr, fileopt); + + if(strFile != "") + { + std::string strFile1 = strFile.toStdString(); + std::string strDir = tl::get_dir(strFile1); + + m_strCurFile = strFile1; + setWindowTitle((s_strTitle + " - " + m_strCurFile).c_str()); + bool bOk = Save(); + + if(bOk) + m_settings.setValue("main/last_dir", QString(strDir.c_str())); + + return bOk; + } + + return false; +} + + + + +//-------------------------------------------------------------------------------- +// importing + +#include "tlibs/file/loadinstr.h" + +bool TazDlg::Import() +{ + QFileDialog::Option fileopt = QFileDialog::Option(0); + if(!m_settings.value("main/native_dialogs", 1).toBool()) + fileopt = QFileDialog::DontUseNativeDialog; + + const bool bShowPreview = m_settings.value("main/dlg_previews", true).toBool(); + QString strDirLast = m_settings.value("main/last_import_dir", ".").toString(); + + QFileDialog *pdlg = nullptr; + if(bShowPreview) + { + pdlg = new FilePreviewDlg(this, "Import Data File...", &m_settings); + pdlg->setOptions(QFileDialog::DontUseNativeDialog); + } + else + { + pdlg = new QFileDialog(this, "Import Data File..."); + pdlg->setOptions(fileopt); + } + std::unique_ptr ptrdlg(pdlg); + + pdlg->setDirectory(strDirLast); + pdlg->setFileMode(QFileDialog::ExistingFile); + pdlg->setViewMode(QFileDialog::Detail); +#if !defined NO_IOSTR + QString strFilter = "Data files (*.dat *.scn *.DAT *.SCN *.ng0 *.NG0 *.log *.LOG *.scn.gz *.SCN.GZ *.dat.gz *.DAT.GZ *.ng0.gz *.NG0.GZ *.log.gz *.LOG.GZ *.scn.bz2 *.SCN.BZ2 *.dat.bz2 *.DAT.BZ2 *.ng0.bz2 *.NG0.BZ2 *.log.bz2 *.LOG.BZ2);;All files (*.*)"; +#else + QString strFilter = "Data files (*.dat *.scn *.DAT *.SCN *.NG0 *.ng0 *.log *.LOG);;All files (*.*)"; +#endif + pdlg->setNameFilter(strFilter); + if(!pdlg->exec()) + return false; + if(!pdlg->selectedFiles().size()) + return false; + + QString strFile = pdlg->selectedFiles()[0]; + if(strFile == "") + return false; + + return Import(strFile.toStdString().c_str()); +} + +bool TazDlg::ImportFile(const QString& strFile) +{ + return Import(strFile.toStdString().c_str()); +} + +bool TazDlg::Import(const char* pcFile) +{ + Disconnect(); + + std::string strFile1 = pcFile; + std::string strDir = tl::get_dir(strFile1); + + std::size_t iScanNum = 0; + try + { + std::unique_ptr> ptrDat( + tl::FileInstrBase::LoadInstr(pcFile)); + tl::FileInstrBase* pdat = ptrDat.get(); + if(!pdat) + return false; + + std::array arrLatt = pdat->GetSampleLattice(); + std::array arrAng = pdat->GetSampleAngles(); + std::array arrSenses = pdat->GetScatterSenses(); + std::array arrD = pdat->GetMonoAnaD(); + std::array arrPeak0 = pdat->GetScatterPlane0(); + std::array arrPeak1 = pdat->GetScatterPlane1(); + + editA->setText(tl::var_to_str(arrLatt[0]).c_str()); + editB->setText(tl::var_to_str(arrLatt[1]).c_str()); + editC->setText(tl::var_to_str(arrLatt[2]).c_str()); + + editAlpha ->setText(tl::var_to_str(tl::r2d(arrAng[0])).c_str()); + editBeta->setText(tl::var_to_str(tl::r2d(arrAng[1])).c_str()); + editGamma->setText(tl::var_to_str(tl::r2d(arrAng[2])).c_str()); + + editMonoD->setText(tl::var_to_str(arrD[0]).c_str()); + editAnaD->setText(tl::var_to_str(arrD[1]).c_str()); + + checkSenseM->setChecked(arrSenses[0]); + checkSenseS->setChecked(arrSenses[1]); + checkSenseA->setChecked(arrSenses[2]); + + editScatX0->setText(tl::var_to_str(arrPeak0[0]).c_str()); + editScatX1->setText(tl::var_to_str(arrPeak0[1]).c_str()); + editScatX2->setText(tl::var_to_str(arrPeak0[2]).c_str()); + + editScatY0->setText(tl::var_to_str(arrPeak1[0]).c_str()); + editScatY1->setText(tl::var_to_str(arrPeak1[1]).c_str()); + editScatY2->setText(tl::var_to_str(arrPeak1[2]).c_str()); + + // spacegroup + std::string strSpaceGroup = pdat->GetSpacegroup(); + tl::trim(strSpaceGroup); + editSpaceGroupsFilter->clear(); + int iSGIdx = comboSpaceGroups->findText(strSpaceGroup.c_str(), Qt::MatchFixedString); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); + else + comboSpaceGroups->setCurrentIndex(0); + + // descr + std::string strExp = pdat->GetTitle(); + std::string strSample = pdat->GetSampleName(); + if(strSample != "") + strExp += std::string(" - ") + strSample; + editDescr->setText(strExp.c_str()); + + iScanNum = pdat->GetScanCount(); + if(iScanNum) + { + InitGoto(); + m_pGotoDlg->ClearList(); + + for(std::size_t iScan=0; iScan arrScan = pdat->GetScanHKLKiKf(iScan); + m_pGotoDlg->AddPosToList(arrScan[0],arrScan[1],arrScan[2],arrScan[3],arrScan[4]); + } + } + } + catch(const std::exception& ex) + { + tl::log_err(ex.what()); + return false; + } + + + m_settings.setValue("main/last_import_dir", QString(strDir.c_str())); + m_strCurFile = /*strFile1*/ ""; // prevents overwriting imported file on saving + setWindowTitle((s_strTitle + " - " + strFile1).c_str()); + + tl::RecentFiles recent(&m_settings, "main/recent_import"); + recent.AddFile(strFile1.c_str()); + recent.SaveList(); + recent.FillMenu(m_pMenuRecentImport, m_pMapperRecentImport); + + CalcPeaks(); + + if(iScanNum && m_pGotoDlg) + { + if(m_pGotoDlg->GotoPos(0)) + { + m_pGotoDlg->show(); + m_pGotoDlg->activateWindow(); + } + } + + return true; +} + +void TazDlg::ShowScanViewer() +{ + if(!m_pScanViewer) + m_pScanViewer = new ScanViewerDlg(this); + + m_pScanViewer->show(); + m_pScanViewer->activateWindow(); +} diff --git a/tools/taz/taz_main.cpp b/tools/taz/taz_main.cpp new file mode 100644 index 0000000..e781fbf --- /dev/null +++ b/tools/taz/taz_main.cpp @@ -0,0 +1,229 @@ +/** + * TAS tool + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#include "taz.h" +#include "tlibs/string/spec_char.h" +#include "tlibs/log/log.h" +#include "tlibs/log/debug.h" +#include "tlibs/time/chrono.h" +#include "tlibs/version.h" +#include "libs/version.h" +#include "libs/globals.h" +#include "dialogs/NetCacheDlg.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +#ifdef Q_WS_X11 + extern "C" int XInitThreads(); +#endif + + +namespace chr = std::chrono; + +static bool add_logfile(std::ofstream* postrLog, bool bAdd=1) +{ + if(!postrLog || !postrLog->is_open()) + { + tl::log_err("Cannot open log file."); + return 0; + } + + for(tl::Log* plog : { &tl::log_info, &tl::log_warn, &tl::log_err, &tl::log_crit, &tl::log_debug }) + { + if(bAdd) + plog->AddOstr(postrLog, 0, 0); + else + plog->RemoveOstr(postrLog); + } + + if(!bAdd) postrLog->operator<<(std::endl); + return 1; +} + +template +static inline void sys_err(const SysErr& err) +{ + tl::log_crit("System error: ", err.what(), + ", category: ", err.code().category().name(), + ", value: ", err.code().value(), "."); + tl::log_backtrace(); +} + + +#define TAKIN_CHECK " Please check if Takin is correctly installed and the current working directory is set to the Takin main directory." + +int main(int argc, char** argv) +{ + try + { + //std::string strLog = QDir::homePath().toStdString(); + std::string strLog = QDir::tempPath().toStdString(); + strLog += "/takin.log"; + std::ofstream ofstrLog(strLog, std::ios_base::out|std::ios_base::app); + if(add_logfile(&ofstrLog, 1)) + tl::log_info("Logging to file \"", strLog, "\"."); + + tl::log_info("Starting up Takin version ", TAKIN_VER, "."); + tl::log_debug("Using ", sizeof(t_real_glob)*8, " bit ", tl::get_typename(), "s as internal data type."); + + + #if defined Q_WS_X11 && !defined NO_3D + XInitThreads(); + QGL::setPreferredPaintEngine(QPaintEngine::OpenGL); + #endif + + // qt needs to be able to copy these structs when emitting signals from a different thread + qRegisterMetaType("TriangleOptions"); + qRegisterMetaType("CrystalOptions"); + qRegisterMetaType("std::string"); + qRegisterMetaType("CacheVal"); + + std::unique_ptr app(new QApplication(argc, argv)); + std::setlocale(LC_ALL, "C"); + std::locale::global(std::locale::classic()); + QLocale::setDefault(QLocale::English); + + QCoreApplication::setApplicationName("Takin"); + QCoreApplication::setApplicationVersion(TAKIN_VER); + std::string strApp = QCoreApplication::applicationDirPath().toStdString(); + tl::log_info("Application path: ", strApp); + + add_resource_path(strApp); + add_resource_path(strApp + "/.."); + add_resource_path(strApp + "/resources"); + add_resource_path(strApp + "/Resources"); + add_resource_path(strApp + "/../resources"); + add_resource_path(strApp + "/../Resources"); + + + // ------------------------------------------------------------ + // tlibs version check + tl::log_info("Using tLibs version ", tl::get_tlibs_version(), "."); + if(!tl::check_tlibs_version(TLIBS_VERSION)) + { + tl::log_crit("Version mismatch in tLibs. Please recompile."); + tl::log_crit("tLibs versions: library: ", tl::get_tlibs_version(), + ", headers: ", TLIBS_VERSION, "."); + + QMessageBox::critical(0, "Takin - Error", "Broken build: Mismatch in tlibs version."); + return -1; + } + + // check tables + g_bHasScatlens = (find_resource("res/scatlens.xml") != ""); + g_bHasFormfacts = (find_resource("res/ffacts.xml") != ""); + g_bHasMagFormfacts = (find_resource("res/magffacts.xml") != ""); + g_bHasSpaceGroups = (find_resource("res/sgroups.xml") != ""); + + if(!g_bHasScatlens) + { + const char* pcErr = "Scattering length table could not be found." TAKIN_CHECK; + tl::log_err(pcErr); + + QMessageBox::critical(0, "Takin - Error", pcErr); + return -1; + } + if(!g_bHasFormfacts) + { + const char* pcErr = "Atomic form factor coefficient table could not be found." TAKIN_CHECK; + tl::log_err(pcErr); + + QMessageBox::critical(0, "Takin - Error", pcErr); + return -1; + } + if(!g_bHasMagFormfacts) + { + const char* pcErr = "Magnetic form factor coefficient table could not be found." TAKIN_CHECK; + tl::log_err(pcErr); + + QMessageBox::critical(0, "Takin - Error", pcErr); + return -1; + } + + if(!g_bHasSpaceGroups) + { + const char* pcErr = "Space group table could not be found!" TAKIN_CHECK; + tl::log_err(pcErr); + + QMessageBox::critical(0, "Takin - Error", pcErr); + return -1; + } + + tl::init_spec_chars(); + + + // check if icons are available + if(find_resource("res/document-new.svg") == "") + { + const char* pcErr = "Takin resources could not be found!" TAKIN_CHECK; + tl::log_err(pcErr); + + QMessageBox::critical(0, "Takin - Error", pcErr); + return -1; + } + + + // ------------------------------------------------------------ + +#ifdef IS_EXPERIMENTAL_BUILD + { + QSettings settings("tobis_stuff", "takin"); + int iPrevDaysSinceEpoch = 0; + if(settings.contains("debug/last_warned")) + iPrevDaysSinceEpoch = settings.value("debug/last_warned").toInt(); + int iDaysSinceEpoch = tl::epoch_dur>().count(); + + std::string strExp = "This " BOOST_PLATFORM " version of Takin is still experimental, " + "does not include all features and may show unexpected behaviour. Please report " + "bugs to tobias.weber@tum.de. Thanks!"; + tl::log_warn(strExp); + //tl::log_debug("Days since last warning: ", iDaysSinceEpoch-iPrevDaysSinceEpoch, "."); + + // show warning message box every 5 days + if(iDaysSinceEpoch - iPrevDaysSinceEpoch > 5) + { + QMessageBox::warning(0, "Takin", strExp.c_str()); + settings.setValue("debug/last_warned", iDaysSinceEpoch); + } + } +#endif + + std::unique_ptr dlg(new TazDlg(0)); + if(argc > 1) + dlg->Load(argv[1]); + dlg->show(); + int iRet = app->exec(); + + + // ------------------------------------------------------------ + tl::deinit_spec_chars(); + tl::log_info("Shutting down Takin."); + add_logfile(&ofstrLog, 0); + + return iRet; + } + catch(const std::system_error& err) { sys_err(err); } + catch(const boost::system::system_error& err) { sys_err(err); } + catch(const std::exception& ex) + { + tl::log_crit("Exception: ", ex.what()); + tl::log_backtrace(); + } + return -1; +} diff --git a/tools/taz/taz_net.cpp b/tools/taz/taz_net.cpp new file mode 100644 index 0000000..401e16b --- /dev/null +++ b/tools/taz/taz_net.cpp @@ -0,0 +1,251 @@ +/* + * TAS tool (server stuff) + * @author tweber + * @date feb-2014 + * @license GPLv2 + */ + +#include "taz.h" + +#include +#include + +#define DEFAULT_MSG_TIMEOUT 4000 + +void TazDlg::ShowConnectDlg() +{ + if(!m_pSrvDlg) + { + m_pSrvDlg = new SrvDlg(this, &m_settings); + QObject::connect(m_pSrvDlg, SIGNAL(ConnectTo(int, const QString&, const QString&, const QString&, const QString&)), + this, SLOT(ConnectTo(int, const QString&, const QString&, const QString&, const QString&))); + } + + m_pSrvDlg->show(); + m_pSrvDlg->activateWindow(); +} + +void TazDlg::ConnectTo(int iSys, const QString& _strHost, const QString& _strPort, + const QString& _strUser, const QString& _strPass) +{ + Disconnect(); + + std::string strHost = _strHost.toStdString(); + std::string strPort = _strPort.toStdString(); + std::string strUser = _strUser.toStdString(); + std::string strPass = _strPass.toStdString(); + + if(iSys == 0) + m_pNetCache = new NicosCache(&m_settings); + else if(iSys == 1) + m_pNetCache = new SicsCache(&m_settings); + else + { + tl::log_err("Unknown instrument control system selected."); + return; + } + + + QObject::connect(m_pNetCache, SIGNAL(vars_changed(const CrystalOptions&, const TriangleOptions&)), + this, SLOT(VarsChanged(const CrystalOptions&, const TriangleOptions&))); + QObject::connect(m_pNetCache, SIGNAL(connected(const QString&, const QString&)), + this, SLOT(Connected(const QString&, const QString&))); + QObject::connect(m_pNetCache, SIGNAL(disconnected()), + this, SLOT(Disconnected())); + + if(!m_pNetCacheDlg) + m_pNetCacheDlg = new NetCacheDlg(this, &m_settings); + + m_pNetCacheDlg->ClearAll(); + QObject::connect(m_pNetCache, SIGNAL(updated_cache_value(const std::string&, const CacheVal&)), + m_pNetCacheDlg, SLOT(UpdateValue(const std::string&, const CacheVal&))); + + // no manual node movement + if(m_sceneReal.GetTasLayout()) m_sceneReal.GetTasLayout()->AllowMouseMove(0); + if(m_sceneTof.GetTofLayout()) m_sceneTof.GetTofLayout()->AllowMouseMove(0); + if(m_sceneRecip.GetTriangle()) m_sceneRecip.GetTriangle()->AllowMouseMove(0); + + m_pNetCache->connect(strHost, strPort, strUser, strPass); +} + +void TazDlg::Disconnect() +{ + if(m_pNetCache) + { + m_pNetCache->disconnect(); + + QObject::disconnect(m_pNetCache, SIGNAL(vars_changed(const CrystalOptions&, const TriangleOptions&)), + this, SLOT(VarsChanged(const CrystalOptions&, const TriangleOptions&))); + QObject::disconnect(m_pNetCache, SIGNAL(connected(const QString&, const QString&)), + this, SLOT(Connected(const QString&, const QString&))); + QObject::disconnect(m_pNetCache, SIGNAL(disconnected()), + this, SLOT(Disconnected())); + + QObject::disconnect(m_pNetCache, SIGNAL(updated_cache_value(const std::string&, const CacheVal&)), + m_pNetCacheDlg, SLOT(UpdateValue(const std::string&, const CacheVal&))); + + delete m_pNetCache; + m_pNetCache = nullptr; + } + + // re-enable manual node movement + if(m_sceneReal.GetTasLayout()) m_sceneReal.GetTasLayout()->AllowMouseMove(1); + if(m_sceneTof.GetTofLayout()) m_sceneTof.GetTofLayout()->AllowMouseMove(1); + if(m_sceneRecip.GetTriangle()) m_sceneRecip.GetTriangle()->AllowMouseMove(1); + + statusBar()->showMessage("Disconnected.", DEFAULT_MSG_TIMEOUT); +} + +void TazDlg::ShowNetCache() +{ + if(!m_pNetCacheDlg) + m_pNetCacheDlg = new NetCacheDlg(this, &m_settings); + + m_pNetCacheDlg->show(); + m_pNetCacheDlg->activateWindow(); +} + +void TazDlg::NetRefresh() +{ + if(m_pNetCache) + m_pNetCache->refresh(); + else + QMessageBox::warning(this, "Warning", "Not connected to an instrument server."); +} + +void TazDlg::Connected(const QString& strHost, const QString& strSrv) +{ + m_strCurFile = ""; + m_vecAtoms.clear(); + + setWindowTitle((s_strTitle + " - ").c_str() + strHost + ":" + strSrv); + statusBar()->showMessage("Connected to " + strHost + " on port " + strSrv + ".", DEFAULT_MSG_TIMEOUT); +} + +void TazDlg::Disconnected() +{ + setWindowTitle((s_strTitle).c_str()); +} + +void TazDlg::VarsChanged(const CrystalOptions& crys, const TriangleOptions& triag) +{ + if(crys.strSampleName != "") + editDescr->setText(tl::trimmed(crys.strSampleName).c_str()); + + if(crys.bChangedLattice) + { + QString qstr0 = QString::number(crys.dLattice[0]); + QString qstr1 = QString::number(crys.dLattice[1]); + QString qstr2 = QString::number(crys.dLattice[2]); + + if(qstr0!=editA->text() || qstr1!=editB->text() || qstr2!=editC->text()) + { + editA->setText(qstr0); + editB->setText(qstr1); + editC->setText(qstr2); + + CalcPeaks(); + } + } + + if(crys.bChangedLatticeAngles) + { + QString qstr0 = QString::number(crys.dLatticeAngles[0]); + QString qstr1 = QString::number(crys.dLatticeAngles[1]); + QString qstr2 = QString::number(crys.dLatticeAngles[2]); + + if(qstr0!=editAlpha->text() || qstr1!=editBeta->text() || qstr2!=editGamma->text()) + { + editAlpha->setText(qstr0); + editBeta->setText(qstr1); + editGamma->setText(qstr2); + + CalcPeaks(); + } + } + + if(crys.bChangedSpacegroup) + { + editSpaceGroupsFilter->clear(); + int iSGIdx = comboSpaceGroups->findText(crys.strSpacegroup.c_str()); + if(iSGIdx >= 0) + comboSpaceGroups->setCurrentIndex(iSGIdx); + else + comboSpaceGroups->setCurrentIndex(0); + + CalcPeaks(); + } + + if(crys.bChangedPlane1) + { + QString qstr0 = QString::number(crys.dPlane1[0]); + QString qstr1 = QString::number(crys.dPlane1[1]); + QString qstr2 = QString::number(crys.dPlane1[2]); + + if(qstr0!=editScatX0->text() || qstr1!=editScatX1->text() || qstr2!=editScatX2->text()) + { + editScatX0->setText(qstr0); + editScatX1->setText(qstr1); + editScatX2->setText(qstr2); + + CalcPeaks(); + } + } + if(crys.bChangedPlane2) + { + QString qstr0 = QString::number(crys.dPlane2[0]); + QString qstr1 = QString::number(crys.dPlane2[1]); + QString qstr2 = QString::number(crys.dPlane2[2]); + + if(qstr0!=editScatY0->text() || qstr1!=editScatY1->text() || qstr2!=editScatY2->text()) + { + editScatY0->setText(qstr0); + editScatY1->setText(qstr1); + editScatY2->setText(qstr2); + + CalcPeaks(); + } + } + + if(triag.bChangedMonoD) + { + QString qstr = QString::number(triag.dMonoD); + if(qstr != editMonoD->text()) + { + editMonoD->setText(qstr); + UpdateDs(); + } + } + if(triag.bChangedAnaD) + { + QString qstr = QString::number(triag.dAnaD); + if(qstr != editAnaD->text()) + { + editAnaD->setText(qstr); + UpdateDs(); + } + } + + + // hack! + if(triag.bChangedTwoTheta && !checkSenseS->isChecked()) + const_cast(triag).dTwoTheta = -triag.dTwoTheta; + + //if(triag.bChangedTwoTheta) + // tl::log_info("2theta: ", triag.dTwoTheta/M_PI*180.); + + m_sceneReal.triangleChanged(triag); + m_sceneReal.emitUpdate(triag); + //m_sceneReal.emitAllParams(); + + UpdateMonoSense(); + UpdateAnaSense(); + UpdateSampleSense(); + + if(triag.bChangedAngleKiVec0) + { + m_sceneRecip.tasChanged(triag); + m_sceneRecip.emitUpdate(); + //m_sceneRecip.emitAllParams(); + } +} diff --git a/tools/taz/taz_nonet.cpp b/tools/taz/taz_nonet.cpp new file mode 100644 index 0000000..bcca3e9 --- /dev/null +++ b/tools/taz/taz_nonet.cpp @@ -0,0 +1,17 @@ +/* + * TAS tool (dummy server stuff) + * @author tweber + * @date mar-2015 + * @copyright GPLv2 + */ + +#include "taz.h" + +void TazDlg::ShowConnectDlg() {} +void TazDlg::ConnectTo(int iSys, const QString& _strHost, const QString& _strPort, const QString& _strUser, const QString& _strPass) {} +void TazDlg::Disconnect() {} +void TazDlg::ShowNetCache() {} +void TazDlg::NetRefresh() {} +void TazDlg::Connected(const QString& strHost, const QString& strSrv) {} +void TazDlg::Disconnected() {} +void TazDlg::VarsChanged(const CrystalOptions& crys, const TriangleOptions& triag) {} diff --git a/tools/taz/tof_layout.cpp b/tools/taz/tof_layout.cpp new file mode 100644 index 0000000..f5ec0e2 --- /dev/null +++ b/tools/taz/tof_layout.cpp @@ -0,0 +1,555 @@ +/** + * TOF layout + * @author tweber + * @date apr-2016 + * @license GPLv2 + */ + +#include "tof_layout.h" +#include "tlibs/string/spec_char.h" +#include + +using t_real = t_real_glob; +using t_vec = ublas::vector; +using t_mat = ublas::matrix; + + +static inline bool flip_text(t_real _dAngle) +{ + t_real dAngle = std::fmod(_dAngle, 360.); + return std::abs(dAngle) > 90. && std::abs(dAngle) < 270.; +} + + +TofLayoutNode::TofLayoutNode(TofLayout* pSupItem) : m_pParentItem(pSupItem) +{ + setFlag(QGraphicsItem::ItemSendsGeometryChanges); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setCursor(Qt::CrossCursor); +} + +QRectF TofLayoutNode::boundingRect() const +{ + return QRectF(-5., -5., 10., 10.); +} + +void TofLayoutNode::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->drawEllipse(QRectF(-2., -2., 4., 4.)); +} + +QVariant TofLayoutNode::itemChange(GraphicsItemChange change, const QVariant &val) +{ + QVariant var = QGraphicsItem::itemChange(change, val); + + if(change == QGraphicsItem::ItemPositionHasChanged) + m_pParentItem->nodeMoved(this); + + return var; +} + +// -------------------------------------------------------------------------------- + +TofLayout::TofLayout(TofLayoutScene& scene) : m_scene(scene) +{ + setFlag(QGraphicsItem::ItemIgnoresTransformations); + + m_pSrc = new TofLayoutNode(this); + m_pSample = new TofLayoutNode(this); + m_pDet = new TofLayoutNode(this); + + m_pSrc->setToolTip("Source"); + m_pSample->setToolTip("Sample"); + m_pDet->setToolTip("Detector"); + + m_pSrc->setPos(0., m_dLenSrcSample*m_dScaleFactor); + m_pSample->setPos(0., 0.); + m_pDet->setPos(-m_dLenSampleDet*m_dScaleFactor, 0.); + + AllowMouseMove(1); + + scene.addItem(m_pSrc); + scene.addItem(m_pSample); + scene.addItem(m_pDet); + + setAcceptedMouseButtons(0); + m_bReady = 1; +} + +TofLayout::~TofLayout() +{ + m_bReady = 0; + + delete m_pSrc; + delete m_pSample; + delete m_pDet; +} + +void TofLayout::AllowMouseMove(bool bAllow) +{ + //m_pSrc->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pSample->setFlag(QGraphicsItem::ItemIsMovable, bAllow); + m_pDet->setFlag(QGraphicsItem::ItemIsMovable, bAllow); +} + +void TofLayout::nodeMoved(const TofLayoutNode *pNode) +{ + if(!m_bReady) return; + + static bool bAllowUpdate = 1; + if(!bAllowUpdate) return; + + const t_vec vecSrc = qpoint_to_vec(mapFromItem(m_pSrc, 0, 0)); + const t_vec vecSample = qpoint_to_vec(mapFromItem(m_pSample, 0, 0)); + const t_vec vecDet = qpoint_to_vec(mapFromItem(m_pDet, 0, 0)); + + bAllowUpdate = 0; + if(pNode == m_pSample) + { + t_real dTwoTheta = m_dTwoTheta; + t_vec vecSrcSample = vecSample - vecSrc; + + if(m_bAllowChanges) + m_dLenSrcSample = ublas::norm_2(vecSrcSample)/m_dScaleFactor; + vecSrcSample /= ublas::norm_2(vecSrcSample); + + + t_vec vecSampleDet = + ublas::prod(tl::rotation_matrix_2d(-dTwoTheta), vecSrcSample); + vecSampleDet /= ublas::norm_2(vecSampleDet); + vecSampleDet *= m_dLenSampleDet*m_dScaleFactor; + + m_pDet->setPos(vec_to_qpoint(vecSample + vecSampleDet)); + vecSampleDet /= ublas::norm_2(vecSampleDet); + + + TriangleOptions opts; + opts.bChangedTwoTheta = 1; + opts.dTwoTheta = dTwoTheta; + m_scene.emitUpdate(opts); + } + if(pNode == m_pDet) + { + t_vec vecSampleDet = vecDet-vecSample; + if(pNode==m_pDet && m_bAllowChanges) + m_dLenSampleDet = ublas::norm_2(vecSampleDet)/m_dScaleFactor; + vecSampleDet /= ublas::norm_2(vecSampleDet); + + t_vec vecSrcSample = vecSample - vecSrc; + vecSrcSample /= ublas::norm_2(vecSrcSample); + + if(m_bAllowChanges) + { + m_dTwoTheta = -(tl::vec_angle(vecSampleDet) - tl::vec_angle(vecSrcSample)); + if(m_dTwoTheta < -tl::get_pi()) m_dTwoTheta += 2.*tl::get_pi(); + if(m_dTwoTheta > tl::get_pi()) m_dTwoTheta -= 2.*tl::get_pi(); + } + + TriangleOptions opts; + opts.bChangedTwoTheta = 1; + opts.dTwoTheta = m_dTwoTheta; + m_scene.emitUpdate(opts); + } + + bAllowUpdate = 1; + this->update(); + m_scene.emitAllParams(); +} + +QRectF TofLayout::boundingRect() const +{ + return QRectF(-1000.*m_dZoom, -1000.*m_dZoom, + 2000.*m_dZoom, 2000.*m_dZoom); +} + + +void TofLayout::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + painter->setFont(g_fontGfx); + const bool bDisplayLengths = 0; + + QPointF ptSrc = mapFromItem(m_pSrc, 0, 0) * m_dZoom; + QPointF ptSample = mapFromItem(m_pSample, 0, 0) * m_dZoom; + QPointF ptDet = mapFromItem(m_pDet, 0, 0) * m_dZoom; + + QLineF lineKi(ptSrc, ptSample); + QLineF lineKf(ptSample, ptDet); + + t_vec vecSrc = qpoint_to_vec(ptSrc); + t_vec vecSample = qpoint_to_vec(ptSample); + t_vec vecDet = qpoint_to_vec(ptDet); + + t_vec vecSrcSample = vecSample-vecSrc; + t_vec vecSampleDet = vecDet-vecSample; + + + QPen penOrig = painter->pen(); + painter->drawLine(lineKi); + painter->drawLine(lineKf); + + + // draw detector bank + QPen penArc(Qt::gray); + penArc.setWidthF(1.5); + painter->setPen(penArc); + + t_real dBaseAngle = tl::r2d(tl::vec_angle(vecSrcSample)); + t_real dLenKf = lineKf.length(); + painter->drawArc(QRectF(ptSample.x()-dLenKf, ptSample.y()-dLenKf, + dLenKf*2., dLenKf*2.), (m_dBeginDetArcAngle-dBaseAngle)*16., m_dDetArcAngle*16.); + + + // draw choppers + QPointF ptChopper1 = ptSrc + (ptSample-ptSrc) * 1./3.; + QPointF ptChopper2 = ptSrc + (ptSample-ptSrc) * 2./3.; + t_vec vecOrthKi(2); + vecOrthKi[0] = vecSrcSample[1]; vecOrthKi[1] = -vecSrcSample[0]; + vecOrthKi /= ublas::norm_2(vecOrthKi); + vecOrthKi *= 0.1*m_dLenSrcSample*m_dZoom*m_dScaleFactor; + painter->drawLine(ptChopper1-vec_to_qpoint(vecOrthKi), ptChopper1+vec_to_qpoint(vecOrthKi)); + painter->drawLine(ptChopper2-vec_to_qpoint(vecOrthKi), ptChopper2+vec_to_qpoint(vecOrthKi)); + + + // write lengths + QPointF ptMidKi = ptSrc + (ptSample-ptSrc)/2.; + QPointF ptMidKf = ptSample + (ptDet-ptSample)/2.; + + if(bDisplayLengths) + { + std::ostringstream ostrLenKi, ostrLenKf; + ostrLenKi.precision(g_iPrecGfx); + ostrLenKf.precision(g_iPrecGfx); + + ostrLenKi << m_dLenSrcSample << " cm"; + ostrLenKf << m_dLenSampleDet << " cm"; + + painter->drawText(ptMidKi, ostrLenKi.str().c_str()); + painter->drawText(ptMidKf, ostrLenKf.str().c_str()); + } + + + // sample theta rotation + t_vec vecRotDir = + ublas::prod(tl::rotation_matrix_2d(-m_dTheta), vecSrcSample); + vecRotDir /= ublas::norm_2(vecRotDir); + vecRotDir *= m_dLenSample*m_dScaleFactor; + + QPointF ptThM = vec_to_qpoint(vecSample - vecRotDir*m_dZoom); + QPointF ptThP = vec_to_qpoint(vecSample + vecRotDir*m_dZoom); + QLineF lineRot = QLineF(ptThM, ptThP); + + QPen pen(Qt::red); + pen.setWidthF(1.5); + painter->setPen(pen); + painter->drawLine(lineRot); + + + // component names + painter->setPen(penOrig); + painter->save(); + painter->translate(vec_to_qpoint(vecSample)); + t_real dCompAngle = 180. + tl::r2d(tl::vec_angle(vecRotDir)); + painter->rotate(dCompAngle); + painter->translate(-4., 16.); + if(flip_text(dCompAngle)) + { + painter->translate(4., -8.); + painter->rotate(180.); + } + painter->drawText(QPointF(0., 0.), "S"); + painter->restore(); + + painter->drawText(ptSample - vec_to_qpoint(vecSrcSample*1.1), "Src"); + painter->drawText(ptSample + vec_to_qpoint(vecSampleDet*1.1), "D"); + painter->drawText(ptChopper1 + vec_to_qpoint(vecOrthKi*2.), "ChP"); + painter->drawText(ptChopper2 + vec_to_qpoint(vecOrthKi*2.), "ChM"); + + + // dashed extended lines + painter->setPen(Qt::DashLine); + QLineF lineki_ext(ptSample, ptSample + (ptSample-ptSrc)/2.); + painter->drawLine(lineki_ext); + //QLineF linekf_ext(ptDet, ptDet + (ptDet-ptSample)/2.); + //painter->drawLine(linekf_ext); + + + + std::unique_ptr plineQ; + std::unique_ptr pptQ; + // Q vector direction visible? + if(this->m_bRealQVisible) + { + //log_info("angle kiQ: ", m_dAngleKiQ/M_PI*180.); + const t_real &dAngleKiQ = m_dAngleKiQ; + t_mat matRotQ = tl::rotation_matrix_2d(dAngleKiQ); + t_vec vecKi = vecSample-vecSrc; + t_vec vecQ = ublas::prod(matRotQ, vecKi); + vecQ /= ublas::norm_2(vecQ); + vecQ *= (m_dLenSrcSample + m_dLenSampleDet)/2.; // some arbitrary length + vecQ *= m_dScaleFactor * m_dZoom; + + pptQ.reset(new QPointF(vec_to_qpoint(vecSample + vecQ))); + plineQ.reset(new QLineF(ptSample, *pptQ)); + + painter->setPen(Qt::red); + painter->drawLine(*plineQ); + painter->save(); + painter->translate(ptSample); + const t_real dQAngle = -plineQ->angle(); + painter->rotate(dQAngle); + painter->translate(QPointF(plineQ->length()/2.,12.)); + if(flip_text(dQAngle)) + painter->rotate(180.); + painter->drawText(QPointF(0,0), "Q"); + painter->restore(); + } + painter->setPen(penOrig); + + + // angle arcs + const QLineF* pLines1[] = {&lineKi, &lineRot}; + const QLineF* pLines2[] = {&lineKf, &lineKi}; + const QPointF* pPoints[] = {&ptSample, &ptSample}; + const QPointF* pPoints_ext[] = {&ptSrc, &ptThP}; + const t_real dAngles[] = {m_dTwoTheta, -m_dTheta}; + const t_real dAngleOffs[] = {0., 180.}; + + QPen pen1(Qt::blue), pen2(Qt::red); + QPen* arcPens[] = {&pen1, &pen2}; + + for(std::size_t i=0; ilength() + pLines2[i]->length()) / 2. / 3.; + t_real dBeginArcAngle = pLines1[i]->angle() + dAngleOffs[i]; + t_real dArcAngle = tl::r2d(dAngles[i]); + + painter->setPen(*arcPens[i]); + painter->drawArc(QRectF(pPoints[i]->x()-dArcSize/2., pPoints[i]->y()-dArcSize/2., + dArcSize, dArcSize), dBeginArcAngle*16., dArcAngle*16.); + + + const std::wstring& strDEG = tl::get_spec_char_utf16("deg"); + std::wostringstream ostrAngle; + ostrAngle.precision(g_iPrecGfx); + if(!tl::is_nan_or_inf(dArcAngle)) + ostrAngle << std::fabs(dArcAngle) << strDEG; + else + ostrAngle << "invalid"; + + + bool bFlip = dAngleOffs[i] > 90.; + t_real dTotalAngle = -dBeginArcAngle-dArcAngle*0.5 + 180.; + if(bFlip) dTotalAngle += 180.; + t_real dTransScale = bFlip ? -40. : 80.; + dTransScale *= m_dZoom; + painter->save(); + painter->translate(*pPoints[i]); + painter->rotate(dTotalAngle); + painter->translate(-dTransScale, +4.); + if(flip_text(dTotalAngle)) + { + if(bFlip) + painter->translate(-dTransScale, -8.); + else + painter->translate(dTransScale*0.5, -8.); + painter->rotate(180.); + } + painter->drawText(QPointF(0.,0.), QString::fromWCharArray(ostrAngle.str().c_str())); + painter->restore(); + } + + painter->setPen(penOrig); + + + // arrow heads + const QLineF* pLines_arrow[] = {&lineKi, &lineKf, plineQ.get()}; + const QPointF* pPoints_arrow[] = {&ptSample, &ptDet, pptQ.get()}; + QColor colArrowHead[] = {Qt::black, Qt::black, Qt::red}; + for(std::size_t i=0; iangle() - 90.); + t_real dC = std::cos(dAng); + t_real dS = std::sin(dAng); + + t_real dTriagX = 5., dTriagY = 10.; + QPointF ptTriag1 = *pPoints_arrow[i] + QPointF(dTriagX*dC + dTriagY*dS, -dTriagX*dS + dTriagY*dC); + QPointF ptTriag2 = *pPoints_arrow[i] + QPointF(-dTriagX*dC + dTriagY*dS, dTriagX*dS + dTriagY*dC); + + QPainterPath triag; + triag.moveTo(*pPoints_arrow[i]); + triag.lineTo(ptTriag1); + triag.lineTo(ptTriag2); + + painter->setPen(colArrowHead[i]); + painter->fillPath(triag, colArrowHead[i]); + } + + painter->setPen(penOrig); +} + + +void TofLayout::SetSampleTwoTheta(t_real dAngle) +{ + m_dTwoTheta = dAngle; + t_vec vecSrc = qpoint_to_vec(mapFromItem(m_pSrc, 0, 0)); + t_vec vecSample = qpoint_to_vec(mapFromItem(m_pSample, 0, 0)); + t_vec vecDet = qpoint_to_vec(mapFromItem(m_pDet, 0, 0)); + + t_vec vecKi = vecSample - vecSrc; + vecKi /= ublas::norm_2(vecKi); + t_real dLenKf = ublas::norm_2(vecDet-vecSample); + + t_vec vecKf = ublas::prod(tl::rotation_matrix_2d(-dAngle), vecKi); + vecKf /= ublas::norm_2(vecKf); + vecKf *= dLenKf; + + m_pDet->setPos(vec_to_qpoint(vecSample + vecKf)); + + nodeMoved(m_pSample); + nodeMoved(m_pDet); +} + +void TofLayout::SetSampleTheta(t_real dAngle) +{ + m_dTheta = dAngle; + nodeMoved(); +} + +void TofLayout::SetAngleKiQ(t_real dAngle) +{ + m_dAngleKiQ = dAngle; + nodeMoved(); +} + +void TofLayout::SetRealQVisible(bool bVisible) +{ + m_bRealQVisible = bVisible; + this->update(); +} + +void TofLayout::SetZoom(t_real dZoom) +{ + m_dZoom = dZoom; + m_scene.update(); +} + +std::vector TofLayout::GetNodes() +{ + return std::vector { m_pSrc, m_pSample, m_pDet }; +} + +std::vector TofLayout::GetNodeNames() const +{ + return std::vector { "source", "sample", "detector" }; +} + +// -------------------------------------------------------------------------------- + + +TofLayoutScene::TofLayoutScene(QObject *pParent) : QGraphicsScene(pParent) +{ + m_pTof = new TofLayout(*this); + this->addItem(m_pTof); +} + +TofLayoutScene::~TofLayoutScene() +{ + delete m_pTof; +} + +void TofLayoutScene::emitAllParams() +{ + if(!m_pTof || !m_pTof->IsReady() || m_bDontEmitChange) + return; + + RealParams parms; + parms.dSampleTT = m_pTof->GetSampleTwoTheta(); + parms.dSampleT = m_pTof->GetSampleTheta(); + //parms.dLenMonoSample = m_pTof->GetLenSrcSample(); + //parms.dLenSampleAna = m_pTof->GetLenSampleDet(); + + emit paramsChanged(parms); +} + +void TofLayoutScene::triangleChanged(const TriangleOptions& opts) +{ + if(!m_pTof || !m_pTof->IsReady()) + return; + + m_bDontEmitChange = 1; + m_pTof->AllowChanges(0); + + if(opts.bChangedTheta) + m_pTof->SetSampleTheta(opts.dTheta); + if(opts.bChangedTwoTheta) + m_pTof->SetSampleTwoTheta(opts.dTwoTheta); + + m_pTof->AllowChanges(1); + m_bDontEmitChange = 0; +} + +void TofLayoutScene::recipParamsChanged(const RecipParams& params) +{ + m_pTof->SetAngleKiQ(params.dKiQ); +} + +void TofLayoutScene::emitUpdate(const TriangleOptions& opts) +{ + if(!m_pTof || !m_pTof->IsReady() || m_bDontEmitChange) + return; + emit tasChanged(opts); +} + +void TofLayoutScene::scaleChanged(t_real dTotalScale) +{ + if(!m_pTof) return; + m_pTof->SetZoom(dTotalScale); +} + +void TofLayoutScene::mousePressEvent(QGraphicsSceneMouseEvent *pEvt) +{ + QGraphicsScene::mousePressEvent(pEvt); + emit nodeEvent(1); +} + +void TofLayoutScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) +{ + QGraphicsScene::mouseReleaseEvent(pEvt); + emit nodeEvent(0); +} + + +// -------------------------------------------------------------------------------- + + +TofLayoutView::TofLayoutView(QWidget* pParent) : QGraphicsView(pParent) +{ + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | + QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + setDragMode(QGraphicsView::ScrollHandDrag); + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); +} + +TofLayoutView::~TofLayoutView() +{} + +void TofLayoutView::wheelEvent(QWheelEvent *pEvt) +{ +#if QT_VER>=5 + const t_real dDelta = pEvt->angleDelta().y()/8. / 150.; +#else + const t_real dDelta = pEvt->delta()/8. / 150.; +#endif + + const t_real dScale = std::pow(2., dDelta); + this->scale(dScale, dScale); + m_dTotalScale *= dScale; + emit scaleChanged(m_dTotalScale); +} + + +#include "tof_layout.moc" diff --git a/tools/taz/tof_layout.h b/tools/taz/tof_layout.h new file mode 100644 index 0000000..fbed6e3 --- /dev/null +++ b/tools/taz/tof_layout.h @@ -0,0 +1,172 @@ +/* + * TOF layout + * @author tweber + * @date apr-2016 + * @license GPLv2 + */ + +#ifndef __TOF_LAYOUT_H__ +#define __TOF_LAYOUT_H__ + +#include "tlibs/helper/flags.h" +#include "libs/globals.h" +#include "libs/globals_qt.h" + +#include +#include +#include +#include +#include +#include +#include +#if QT_VER>=5 + #include +#endif + +#include "tasoptions.h" +#include "dialogs/RealParamDlg.h" // for RealParams struct +#include "dialogs/RecipParamDlg.h" // for RecipParams struct + + +class TofLayout; +class TofLayoutNode : public QGraphicsItem +{ + protected: + TofLayout *m_pParentItem; + + protected: + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &val) override; + + public: + TofLayoutNode(TofLayout* pSupItem); +}; + + +class TofLayoutScene; +class TofLayout : public QGraphicsItem +{ + protected: + bool m_bReady = 0; + TofLayoutScene& m_scene; + + TofLayoutNode *m_pSrc = nullptr; + TofLayoutNode *m_pSample = nullptr; + TofLayoutNode *m_pDet = nullptr; + + t_real_glob m_dTwoTheta = 3.1415/2.; + t_real_glob m_dTheta = 3.1415/4.; + t_real_glob m_dAngleKiQ = 3.1415/4.; + + t_real_glob m_dLenSrcSample = 150.; + t_real_glob m_dLenSampleDet = 100.; + t_real_glob m_dLenSample = 25.; + + t_real_glob m_dBeginDetArcAngle = -140.; + t_real_glob m_dDetArcAngle = -m_dBeginDetArcAngle*2.; + + t_real_glob m_dScaleFactor = 1.4; // pixels per cm for zoom == 1 + t_real_glob m_dZoom = 1.; + + bool m_bRealQVisible = 1; + bool m_bAllowChanges = 1; + + public: + t_real_glob GetSampleTwoTheta() const { return m_dTwoTheta; } + t_real_glob GetSampleTheta() const { return m_dTheta; } + t_real_glob GetLenSrcSample() const { return m_dLenSrcSample; } + t_real_glob GetLenSampleDet() const { return m_dLenSampleDet; } + + protected: + QRectF boundingRect() const override; + + public: + TofLayout(TofLayoutScene& scene); + virtual ~TofLayout(); + + bool IsReady() const { return m_bReady; } + + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + + void SetSampleTwoTheta(t_real_glob dTT); + void SetSampleTheta(t_real_glob dT); + void SetAngleKiQ(t_real_glob dKiQ); + + void SetReady(bool bReady) { m_bReady = bReady; } + void nodeMoved(const TofLayoutNode* pNode=0); + + void AllowChanges(bool bAllow) { m_bAllowChanges = bAllow; }; + void AllowMouseMove(bool bAllow); + + void SetZoom(t_real_glob dZoom); + t_real_glob GetZoom() const { return m_dZoom; } + + public: + std::vector GetNodes(); + std::vector GetNodeNames() const; + + t_real_glob GetScaleFactor() const { return m_dScaleFactor; } + void SetScaleFactor(t_real_glob dScale) { m_dScaleFactor = dScale; } + + void SetRealQVisible(bool bVisible); + bool GetRealQVisible() const { return m_bRealQVisible; } +}; + + +class TofLayoutScene : public QGraphicsScene +{ Q_OBJECT + protected: + TofLayout *m_pTof; + bool m_bDontEmitChange = 1; + + protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *pEvt) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *pEvt) override; + + + public: + TofLayoutScene(QObject *pParent=nullptr); + virtual ~TofLayoutScene(); + + void SetEmitChanges(bool bEmit) { m_bDontEmitChange = !bEmit; } + void emitUpdate(const TriangleOptions& opts); + + TofLayout* GetTofLayout() { return m_pTof; } + + void emitAllParams(); + + public slots: + void triangleChanged(const TriangleOptions& opts); + void scaleChanged(t_real_glob dTotalScale); + + void recipParamsChanged(const RecipParams& params); + + signals: + // relevant parameters for triangle view + void tasChanged(const TriangleOptions& opts); + // all parameters + void paramsChanged(const RealParams& parms); + + void nodeEvent(bool bStarted); +}; + + +class TofLayoutView : public QGraphicsView +{ + Q_OBJECT + protected: + t_real_glob m_dTotalScale = 1.; + virtual void wheelEvent(QWheelEvent* pEvt) override; + + public: + TofLayoutView(QWidget* pParent = 0); + virtual ~TofLayoutView(); + + signals: + void scaleChanged(t_real_glob dTotalScale); +}; + + +#endif diff --git a/tools/test/sqw.py b/tools/test/sqw.py new file mode 120000 index 0000000..4ebd46d --- /dev/null +++ b/tools/test/sqw.py @@ -0,0 +1 @@ +../../examples/sqw_py/sqw.py \ No newline at end of file diff --git a/tools/test/tst_cl.cpp b/tools/test/tst_cl.cpp new file mode 100644 index 0000000..864298a --- /dev/null +++ b/tools/test/tst_cl.cpp @@ -0,0 +1,199 @@ +// tests all available cl devices +// gcc -o tst_cl tst_cl.cpp -lstdc++ -lOpenCL -std=c++11 +// @author tw + +#include +#include + +//#define USE_DOUBLE + +#ifdef USE_DOUBLE + typedef double t_real; +#else + typedef float t_real; +#endif + +static const std::string strAux = +R"RAW( +#ifdef USE_DOUBLE + #pragma OPENCL EXTENSION cl_khr_fp64: enable + typedef double t_real; +#else + typedef float t_real; +#endif + + static void copy(int iSize, __global t_real *pdOut, const __global t_real *pdIn) + { + for(int i=0; i vecPlat; + cl::Platform::get(&vecPlat); + std::cout << "Found " << vecPlat.size() << " platforms." << std::endl; + std::cout << "------------------------------------------------------------" << std::endl; + + for(cl::Platform& plat : vecPlat) + { + std::string strVendor, strName, strVer, strProf, strExt; + plat.getInfo(CL_PLATFORM_VENDOR, &strVendor); + plat.getInfo(CL_PLATFORM_NAME, &strName); + plat.getInfo(CL_PLATFORM_VERSION, &strVer); + plat.getInfo(CL_PLATFORM_PROFILE, &strProf); + plat.getInfo(CL_PLATFORM_EXTENSIONS, &strExt); + + std::cout << "Platform: " << strVendor << ", " << strName << ", " + << strVer << ", " << strProf << std::endl; + std::cout << "Extensions: " << strExt << std::endl; + + std::vector vecDevCPU, vecDevGPU, vecDevAccel; + plat.getDevices(CL_DEVICE_TYPE_CPU, &vecDevCPU); + plat.getDevices(CL_DEVICE_TYPE_GPU, &vecDevGPU); + plat.getDevices(CL_DEVICE_TYPE_ACCELERATOR, &vecDevAccel); + + std::cout << "Found " << vecDevCPU.size() << " CPUs, " + << vecDevGPU.size() << " GPUs and " + << vecDevAccel.size() << " accelerators." + << std::endl; + + std::vector vecDevs = vecDevCPU; + vecDevs.insert(vecDevs.end(), vecDevGPU.begin(), vecDevGPU.end()); + vecDevs.insert(vecDevs.end(), vecDevAccel.begin(), vecDevAccel.end()); + + for(cl::Device& dev : vecDevs) + { + std::string strDevName, strExtens; + cl_uint iUnits, iWIDims; + cl_ulong lGlobMem, lLocMem; + std::size_t iWGSize; + dev.getInfo(CL_DEVICE_NAME, &strDevName); + dev.getInfo(CL_DEVICE_MAX_COMPUTE_UNITS, &iUnits); + dev.getInfo(CL_DEVICE_EXTENSIONS, &strExtens); + dev.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &lGlobMem); + dev.getInfo(CL_DEVICE_LOCAL_MEM_SIZE, &lLocMem); + dev.getInfo(CL_DEVICE_MAX_WORK_GROUP_SIZE, &iWGSize); + dev.getInfo(CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, &iWIDims); + + std::cout << "\n"; + std::cout << "Device: " << strDevName << std::endl; + std::cout << "Extensions: " << strExtens << std::endl; + std::cout << "Number of computation units: " << iUnits << std::endl; + std::cout << "Global memory: " << lGlobMem << " bytes" << std::endl; + std::cout << "Local memory: " << lLocMem << " bytes" << std::endl; + std::cout << "Maximum workgroup size: " << iWGSize << std::endl; + std::cout << "Maximum workitem dim: " << iWIDims << std::endl; + + + std::cout << "\nExecuting test kernel." << std::endl; + + std::vector vecDevsCont = {dev}; + cl::Context cont(vecDevsCont); + + + cl::Program::Sources vecSrc = + { + std::pair(strAux.c_str(), strAux.length()), + std::pair(strProg.c_str(), strProg.length()) + }; + + cl_int iErr, iErr2; + cl::Program prog(cont, vecSrc, &iErr); + if(iErr < 0) + { + std::cerr << "Error: Cannot create program." << std::endl; + continue; + } + + std::string strOpts = ""; +#ifdef USE_DOUBLE + strOpts += "-DUSE_DOUBLE"; +#endif + + iErr = prog.build(strOpts.c_str()); + if(iErr < 0) + { + std::string strErrLog; + prog.getBuildInfo(dev, CL_PROGRAM_BUILD_LOG, &strErrLog); + + std::cerr << "Error: Cannot build program." << std::endl; + std::cerr << "Log: " << strErrLog << std::endl; + continue; + } + + + cl::Kernel kern(prog, bUseLoop ? "tst_cl_kern_loop" : "tst_cl_kern", &iErr); + if(iErr < 0) + { + std::cerr << "Error: Cannot create kernel." << std::endl; + continue; + } + + cl::CommandQueue qu(cont, dev, 0, &iErr); + if(iErr < 0) + { + std::cerr << "Error: Cannot create command queue." << std::endl; + continue; + } + + t_real dIn[] = {1., 2., 3., 4.}; + t_real dOut[4]; + + cl::Buffer bufVecIn(cont, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, sizeof dIn, dIn, &iErr); + cl::Buffer bufVecOut(cont, CL_MEM_WRITE_ONLY, sizeof dIn, nullptr, &iErr2); + if(iErr<0 || iErr2<0) + { + std::cerr << "Error: Cannot create input/output buffers." << std::endl; + continue; + } + + kern.setArg(0, bufVecIn); + kern.setArg(1, bufVecOut); + + cl::Event evtKern, evtOut; + cl::NDRange ranOffs, ranGlob(4), ranLoc; + if(bUseLoop) + qu.enqueueTask(kern, 0, &evtKern); + else + qu.enqueueNDRangeKernel(kern, ranOffs, ranGlob, ranLoc, 0, &evtKern); + + std::vector vecEvts = {evtKern}; + qu.enqueueReadBuffer(bufVecOut, 0, 0, sizeof dOut, dOut, &vecEvts, &evtOut); + evtKern.wait(); evtOut.wait(); + + std::cout << "Result: 2 * (1 2 3 4) = "; + for(int i=0; i<4; ++i) + std::cout << dOut[i] << " "; + std::cout << std::endl; + } + + std::cout << "------------------------------------------------------------" << std::endl; + } + + return 0; +} diff --git a/tools/test/tst_clipper.cpp b/tools/test/tst_clipper.cpp new file mode 100644 index 0000000..993faeb --- /dev/null +++ b/tools/test/tst_clipper.cpp @@ -0,0 +1,128 @@ +// gcc -o tst_clipper tst_clipper.cpp -lstdc++ -lm -lclipper-core -std=c++11 + +#include +#include "../../tlibs/math/atoms.h" +#include "../../tlibs/helper/array.h" + + +void list_sgs() +{ + for(int iSg=1; iSg<=230; ++iSg) + { + clipper::Spgr_descr dsc(iSg); + std::cout << "Spacegroup " << iSg << ": " << dsc.symbol_hm() << std::endl; + } +} + +void test_hkls() +{ + std::string strSg; + + std::cout << "Enter spacegroup: "; + std::getline(std::cin, strSg); + clipper::Spgr_descr dsc(strSg); + int iSGNum = dsc.spacegroup_number(); + if(iSGNum <= 0) + { + std::cerr << "Error: Unknown Spacegroup." << std::endl; + return; + } + + std::cout << "Nr.: " << iSGNum << std::endl; + std::cout << "Hall: " << dsc.symbol_hall() << std::endl; + std::cout << "HM: " << dsc.symbol_hm() << std::endl; + + clipper::Spacegroup sg(dsc); + std::cout << "Laue group: " << sg.symbol_laue() << std::endl; + + int iNumSymOps = sg.num_symops(); + std::cout << "Number of symmetry operations: " << iNumSymOps << std::endl; + for(int iSymOp=0; iSymOp> h >> k >> l; + clipper::HKL_class hkl = sg.hkl_class(clipper::HKL(h,k,l)); + + std::cout << "allowed: " << (!hkl.sys_abs()) << std::endl; + std::cout << "centric: " << hkl.centric() << std::endl; + std::cout << "allowed phase: " << hkl.allowed() << std::endl; + std::cout << "epsilon: " << hkl.epsilon() << std::endl; + std::cout << std::endl; + } +} + + +// ---------------------------------------------------------------------------- + + +// ugly, but can't be helped for the moment: +// directly link to the internal clipper coefficients table +// that lives in clipper/clipper/core/atomsf.cpp +namespace clipper { namespace data +{ + extern const struct SFData + { + const char atomname[8]; + const double a[5], c, b[5], d; // d is always 0 + } sfdata[]; + + const int numsfdata = 212; +}} + + +void ffact() +{ + /*for(int i=0; i(G, a, b, c); + std::cout << G << "\t" << ff << "\n"; + } + std::cout.flush(); +} + + +// ---------------------------------------------------------------------------- + + +int main() +{ + try + { + //list_sgs(); + //test_hkls(); + + ffact(); + } + catch(const clipper::Message_fatal& ex) + { + std::cerr << "Fatal error." << std::endl; + } + catch(const std::exception& ex) + { + std::cerr << "Error: " << ex.what() << std::endl; + } + + return 0; +} diff --git a/tools/test/tst_cov.cpp b/tools/test/tst_cov.cpp new file mode 100644 index 0000000..3d7828f --- /dev/null +++ b/tools/test/tst_cov.cpp @@ -0,0 +1,32 @@ +// clang -I../.. -I. -o tst_cov tst_cov.cpp -lstdc++ -lm -std=c++11 + +#include +#include +#include +#include +#include "tlibs/math/linalg.h" + +using namespace tl; + +int main() +{ + std::vector> vals + { + make_vec({1.0, 2.0, 3.0}), + make_vec({1.1, 2.2, 3.4}), + make_vec({0.9, 1.8, 2.9}), + make_vec({1.0, 2.1, 3.1}), + make_vec({1.4, 2.1, 3.6}), + }; + + std::vector vecProb = { 1./5., 1./5., 1./5., 1./5., 1./5.}; + + std::cout << "Measured values:\n"; + std::copy(vals.begin(), vals.end(), std::ostream_iterator(std::cout,"\n")); + std::cout << std::endl; + + ublas::matrix mat = covariance(vals, &vecProb); + std::cout << "Covariance matrix:\n" << mat << std::endl; + + return 0; +} diff --git a/tools/test/tst_for.cpp b/tools/test/tst_for.cpp new file mode 100644 index 0000000..4ce97dd --- /dev/null +++ b/tools/test/tst_for.cpp @@ -0,0 +1,25 @@ +// gcc -o tst_for tst_for.cpp tst_for.o -lstdc++ -lgfortran + +#include +#include + +extern "C" void add_(double *a, double *b, double *res) __attribute__((stdcall)); +extern "C" double sub_(double *a, double *b) __attribute__((stdcall)); +extern "C" void pr_(char* str) __attribute__((stdcall)); + +int main() +{ + char pc[] = "1234567890"; + pr_(pc); + + double a, b, res, res2; + std::cout << "a = "; std::cin >> a; + std::cout << "b = "; std::cin >> b; + + add_(&a, &b, &res); + res2 = sub_(&a, &b); + + std::cout << "add: " << res << std::endl; + std::cout << "sub: " << res2 << std::endl; + return 0; +} diff --git a/tools/test/tst_for.for b/tools/test/tst_for.for new file mode 100644 index 0000000..7b77fcf --- /dev/null +++ b/tools/test/tst_for.for @@ -0,0 +1,26 @@ +! gfortran -c -ffree-form -o tst_for.o tst_for.for + +subroutine add(a,b, result) + real*8 a, b, result + + result = a+b + + return + end + + +subroutine pr(str) + character str(5) + + print *, "Got string: ", str + + return + end + + +function sub(a,b) + real*8 a,b, result + + result = a-b + return + end diff --git a/tools/test/tst_geo.cpp b/tools/test/tst_geo.cpp new file mode 100644 index 0000000..c73cc57 --- /dev/null +++ b/tools/test/tst_geo.cpp @@ -0,0 +1,70 @@ +// gcc -DUSE_LAPACK -o tst_geo tst_geo.cpp -std=c++11 -lstdc++ -lm -I../.. -I. -I/usr/include/lapacke ../../tlibs/log/log.cpp ../../tlibs/math/linalg2.cpp -llapacke -llapack + +#include "tlibs/math/geo.h" +#include "tlibs/math/math.h" +#include "tlibs/math/linalg2.h" + +using namespace tl; + +typedef ublas::vector vec; + + +void tst0() +{ + vec v0(3), dir0_0(3), dir0_1(3); + vec v1(3), dir1_0(3), dir1_1(3); + + v0[0] = 0.; v0[1] = 0.; v0[2] = 0.; + v1[0] = 3.; v1[1] = 0.; v1[2] = 0.; + + dir0_0[0] = 1.; dir0_0[1] = 0.; dir0_0[2] = 0.; + dir0_1[0] = 0.; dir0_1[1] = 1.; dir0_1[2] = 0.; + + dir1_0[0] = 0.; dir1_0[1] = 1.; dir1_0[2] = 0.; + dir1_1[0] = 0.; dir1_1[1] = 0.; dir1_1[2] = 1.; + + Plane plane0(v0, dir0_0, dir0_1); + Plane plane1(v1, dir1_0, dir1_1); + + std::cout << "Plane 0: " << plane0 << std::endl; + std::cout << "Plane 1: " << plane1 << std::endl; + + Line line; + if(plane0.intersect(plane1, line)) + std::cout << "Line: " << line << std::endl; + else + std::cout << "Error." << std::endl; +} + +void tst1() +{ + ublas::vector vecPos(2), vecDir(2); + vecPos[0] = 0.; + vecPos[1] = 0.; + + vecDir[0] = 1.; + vecDir[1] = 1.; + + + Line line(vecPos, vecDir); + ublas::vector v0(2), v1(2); + v0[0] = -1.; + v0[1] = 1.; + + v1[0] = 2.; + v1[1] = 1.; + + double dDist0, dDist1; + std::cout << "side: " << line.GetSide(v0, &dDist0); + std::cout << ", dist: " << dDist0 << std::endl; + std::cout << "side: " << line.GetSide(v1, &dDist1); + std::cout << ", dist: " << dDist1 << std::endl; +} + +int main() +{ + //tst0(); + tst1(); + + return 0; +} diff --git a/tools/test/tst_hkl.cpp b/tools/test/tst_hkl.cpp new file mode 100644 index 0000000..fd565e2 --- /dev/null +++ b/tools/test/tst_hkl.cpp @@ -0,0 +1,57 @@ +// gcc -I../.. -o tst_hkl tst_hkl.cpp ../../tlibs/log/log.cpp -lstdc++ -std=c++11 -lm + +#include +#include "tlibs/math/lattice.h" + +using namespace tl; + +typedef ublas::vector t_vec; + + +int main() +{ + double a = 5.; + double b = 4.; + double c = 3.; + double alpha = 90.; + double beta = 90.; + double gamma = 60.; + + double dKi = 2.66; + double dKf = 2.66; + + double dh = 2.; + double dk = 0.; + double dl = 1.; + + t_vec vec1 = make_vec({1., -1., 0.}); + t_vec vec2 = make_vec({1., 1., 1.}); + + Lattice lat(a,b,c, alpha/180.*M_PI,beta/180.*M_PI,gamma/180.*M_PI); + //Lattice rec = lat.GetRecip(); + //Lattice rec_aligned = rec.GetAligned(); + + std::cout << "lattice: " << lat << std::endl; + //std::cout << "recip: " << rec << std::endl; + //std::cout << "recip (aligned): " << rec_aligned << std::endl; + + std::cout << "vec1 = " << vec1 << std::endl; + std::cout << "vec2 = " << vec2 << std::endl; + + + double dTheta, d2Theta; + + try + { + get_tas_angles(lat, vec1,vec2, dKi,dKf, dh,dk,dl, 1, &dTheta, &d2Theta); + } + catch(const std::exception& ex) + { + std::cerr << ex.what() << std::endl; + return -1; + } + + std::cout << "theta = " << dTheta/M_PI*180. << " deg" << std::endl; + std::cout << "2theta = " << d2Theta/M_PI*180. << " deg" << std::endl; + return 0; +} diff --git a/tools/test/tst_py.cpp b/tools/test/tst_py.cpp new file mode 100644 index 0000000..4c51f53 --- /dev/null +++ b/tools/test/tst_py.cpp @@ -0,0 +1,67 @@ +//gcc -std=c++11 -I /usr/include/python2.7 -o tst_py tst_py.cpp -lstdc++ -lboost_python -lpython2.7 + +#include + +#include +namespace py = boost::python; + + +void list_keys(py::dict dict) +{ + std::cout << py::len(dict.items()) << " keys in dict:" << std::endl; + for(int i=0; i(dict.items()[i][0])) + << std::endl; + } +} + +void call_py_fkt() +{ + try + { + py::object sys = py::import("sys"); + py::dict sysdict = py::extract(sys.attr("__dict__")); + py::list path = py::extract(sysdict["path"]); + path.append("."); + + py::object mod = py::import("sqw"); + py::dict moddict = py::extract(mod.attr("__dict__")); + py::object Sqw = moddict["TakinSqw"]; + + for(double dE=0.; dE<1.; dE+=0.1) + { + double dS = py::extract(Sqw(1., 1., 1., dE)); + std::cout << dS << std::endl; + } + + + + py::object mn = py::import("__main__"); + py::dict mndict = py::extract(mn.attr("__dict__")); + + std::cout << "\nmain dict:\n"; + list_keys(mndict); + + //std::cout << "\nsys dict:\n"; + //list_keys(sysdict); + + std::cout << "\nmod dict:\n"; + list_keys(moddict); + } + catch(const py::error_already_set& ex) + { + PyErr_Print(); + PyErr_Clear(); + } +} + + +int main(int argc, char** argv) +{ + Py_Initialize(); + call_py_fkt(); + + //Py_Finalize(); + return 0; +} diff --git a/tools/test/tst_qr.cpp b/tools/test/tst_qr.cpp new file mode 100644 index 0000000..0546981 --- /dev/null +++ b/tools/test/tst_qr.cpp @@ -0,0 +1,32 @@ +// gcc -I../.. -DUSE_LAPACK -o tst_qr tst_qr.cpp ../../tlibs/math/linalg2.cpp ../../tlibs/log/log.cpp -std=c++11 -lstdc++ -lm -I/usr/include/lapacke -llapacke -llapack + +#include "tlibs/math/linalg.h" +#include "tlibs/math/linalg2.h" + +using namespace tl; + +typedef ublas::vector vec; +typedef ublas::matrix mat; + +int main() +{ + mat M(2,4); + M(0,0)=1; M(0,1)=8; M(0,2)=2; M(0,3)=0; + M(1,0)=2; M(1,1)=0; M(1,2)=2; M(1,3)=1; + //M = ublas::trans(M); + std::cout << "M = " << M << std::endl; + //std::cout << "Msub = " << remove_column(M,0) << std::endl; + //std::cout << ublas::subrange(M,0,2,2,4) << std::endl; + + mat Q, R; + bool bOk = qr(M, Q, R); + std::cout << "OK = " << bOk << std::endl; + + std::cout << "\nQ = " << Q << std::endl; + std::cout << "det(Q) = " << determinant(Q) << std::endl; + std::cout << "R = " << R << std::endl; + + std::cout << "\nQR = " << ublas::prod(Q,R) << std::endl; + std::cout << "Q'Q = " << ublas::prod(ublas::trans(Q),Q) << std::endl; + return 0; +} diff --git a/tools/test/tst_quad.cpp b/tools/test/tst_quad.cpp new file mode 100644 index 0000000..1d11a07 --- /dev/null +++ b/tools/test/tst_quad.cpp @@ -0,0 +1,41 @@ +// gcc -I../.. -I/usr/include/lapacke -o tst_quad tst_quad.cpp ../../tlibs/math/linalg2.cpp ../../tlibs/log/log.cpp -lstdc++ -lm -llapacke -llapack -std=c++11 + +#include "tlibs/math/linalg.h" +#include "tlibs/math/geo.h" +#include + +using namespace tl; + +int main() +{ + QuadEllipsoid elli(1.,2.,3.,4.); + std::cout << "quad: " << elli << std::endl; + + Quadric q2 = elli; + q2.RemoveElems(1); + std::cout << "removed 1: " << q2 << std::endl; + + ublas::matrix matRot = rotation_matrix_3d_y(0.5); + matRot.resize(4,4,1); + matRot(3,0)=matRot(3,1)=matRot(3,2)=matRot(0,3)=matRot(1,3)=matRot(2,3)=0.; + matRot(3,3)=1.; + std::cout << "trafo: " << matRot << std::endl; + + elli.transform(matRot); + std::cout << "quad: " << elli << std::endl; + + + ublas::matrix matEvecs; + std::vector vecEvals; + elli.GetPrincipalAxes(matEvecs, vecEvals); + ublas::matrix matEvals = diag_matrix(vecEvals); + + std::cout << "evecs: " << matEvecs << std::endl; + std::cout << "evals: " << matEvals << std::endl; + + + ublas::matrix mat0 = ublas::prod(matEvals, ublas::trans(matEvecs)); + std::cout << "reconstr. quad: " << ublas::prod(matEvecs, mat0) << std::endl; + + return 0; +} diff --git a/tools/test/tst_quat.cpp b/tools/test/tst_quat.cpp new file mode 100644 index 0000000..60dfe21 --- /dev/null +++ b/tools/test/tst_quat.cpp @@ -0,0 +1,76 @@ +// gcc -I../.. -o tst_quat tst_quat.cpp -lstdc++ -lm -std=c++11 + +#include + +#include "tlibs/math/linalg.h" +#include "tlibs/math/quat.h" + +using namespace tl; + +int main() +{ + //ublas::matrix rot = rotation_matrix(make_vec({1.,1.,1.}), 1.23); + ublas::matrix rot = rotation_matrix_3d_x(1.23); + math::quaternion quat = rot3_to_quat(rot); + ublas::matrix rot2 = quat_to_rot3(quat); + + std::cout << "rot: " << rot << std::endl; + std::cout << "quat: " << quat << std::endl; + std::cout << "rot2: " << rot2 << std::endl; + + + double dAngle = 1.23; + math::quaternion quata = rotation_quat_x(dAngle); + ublas::matrix rota = quat_to_rot3(quata); + std::cout << std::endl; + std::cout << "quat a: " << quata << std::endl; + std::cout << "rot a: " << rota << std::endl; + std::cout << "angle a (quat): " << rotation_angle(quata) << std::endl; + std::cout << "axis a (quat): " << rotation_axis(quata) << std::endl; + std::cout << "angle a (mat): " << std::acos(rota(2,2)) << std::endl; + + + ublas::vector vecAxis = make_vec({1., 0., 0.}); + math::quaternion quatb = rotation_quat(vecAxis, 1.23); + ublas::matrix rotb = quat_to_rot3(quatb); + std::cout << std::endl; + std::cout << "quat b: " << quatb << std::endl; + std::cout << "rot b: " << rotb << std::endl; + std::cout << "angle b (quat): " << rotation_angle(quatb) << std::endl; + std::cout << "axis b (quat): " << rotation_axis(quatb) << std::endl; + std::cout << "angle b (mat): " << std::acos(rotb(2,2)) << std::endl; + + + ublas::vector vecAxis2 = make_vec({1., 1., 0.}); + math::quaternion quatc = rotation_quat(vecAxis2, 1.23); + ublas::matrix matc = rotation_matrix(vecAxis2, 1.23); + ublas::matrix rotc = quat_to_rot3(quatc); + std::cout << std::endl; + std::cout << "quat c: " << quatc << std::endl; + std::cout << "rot c: " << rotc << std::endl; + std::cout << "mat c: " << matc << std::endl; + std::cout << "angle c (quat): " << rotation_angle(quatc) << std::endl; + std::cout << "axis c (quat): " << rotation_axis(quatc) << std::endl; + + + + math::quaternion q1(0,1,0,0); + math::quaternion q2(0,0,1,0); + + std::cout << std::endl; + std::cout << "slerp 0: " << slerp(q1, q2, 0.) << std::endl; + std::cout << "slerp 0.5: " << slerp(q1, q2, 0.5) << std::endl; + std::cout << "slerp 1: " << slerp(q1, q2, 1.) << std::endl; + + std::cout << std::endl; + std::cout << "lerp 0: " << lerp(q1, q2, 0.) << std::endl; + std::cout << "lerp 0.5: " << lerp(q1, q2, 0.5) << std::endl; + std::cout << "lerp 1: " << lerp(q1, q2, 1.) << std::endl; + + + std::cout << std::endl; + math::quaternion quat_s = stereo_proj(quat); + std::cout << "stereo proj: " << quat_s << std::endl; + std::cout << "inv stereo proj: " << stereo_proj_inv(quat_s) << std::endl; + return 0; +} diff --git a/tools/test/tst_quat2.cpp b/tools/test/tst_quat2.cpp new file mode 100644 index 0000000..ca85094 --- /dev/null +++ b/tools/test/tst_quat2.cpp @@ -0,0 +1,121 @@ +// moc-qt5 tst_quat2.cpp > tst_quat2.moc && gcc -fPIC -I. -I../.. -I/usr/include/qt5 -I/usr/include/freetype2 -o tst_quat2 tst_quat2.cpp -lstdc++ -lm -lQt5Core -lQt5Gui -lQt5OpenGL -lQt5Widgets -lGL -std=c++14 + +#include + +#include "tlibs/math/linalg.h" +#include "tlibs/math/quat.h" +#include "tlibs/gfx/gl.h" + +#include +#include +#include +#include +#include +#include + +using namespace tl; + +typedef ublas::matrix> t_mat4; +typedef ublas::matrix> t_mat3; + +class GlWidget : public QGLWidget /*QOpenGLWidget*/ +{ Q_OBJECT + protected: + QOpenGLFunctions_2_1 *m_pGL = 0; + double m_dTick = 0.; + QTimer m_timer; + + protected slots: + void tick() + { + m_dTick += 0.02; + update(); + } + + public: + GlWidget(QWidget* pParent) : QGLWidget/*QOpenGLWidget*/(pParent), m_timer(this) + { + QObject::connect(&m_timer, &QTimer::timeout, this, &GlWidget::tick); + m_timer.start(5); + } + virtual ~GlWidget() + { + m_timer.stop(); + } + + protected: + virtual void initializeGL() override + { + m_pGL = QOpenGLContext::currentContext()->versionFunctions(); + m_pGL->initializeOpenGLFunctions(); + + m_pGL->glClearColor(1.,1.,1.,0.); + m_pGL->glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + m_pGL->glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + m_pGL->glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + m_pGL->glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + } + + virtual void resizeGL(int w, int h) override + { + if(w<=0) w=1; if(h<=0) h=1; + m_pGL->glViewport(0,0,w,h); + + m_pGL->glMatrixMode(GL_PROJECTION); + //t_mat4 mat = perspective_matrix(45./180.*M_PI, double(w)/double(h), 0.1, 100.); + //GLdouble glmat[16]; to_gl_array(mat, glmat); + //m_pGL->glLoadMatrixd(glmat); + m_pGL->glLoadIdentity(); + + m_pGL->glMatrixMode(GL_MODELVIEW); + m_pGL->glLoadIdentity(); + } + + virtual void paintGL() override + { + m_pGL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_pGL->glPushMatrix(); + + m_pGL->glTranslated(0., 0., -0.5); + + t_mat3 mat0 = rotation_matrix_3d_z(0.); + t_mat3 mat1 = rotation_matrix_3d_z(M_PI/2.); + + math::quaternion quat0 = rot3_to_quat(mat0); + math::quaternion quat1 = rot3_to_quat(mat1); + math::quaternion quat = slerp(quat0, quat1, m_dTick); + //math::quaternion quat = lerp(quat0, quat1, m_dTick); + + t_mat3 mat = quat_to_rot3(quat); + GLdouble glmat[16]; to_gl_array(mat, glmat); + m_pGL->glMultMatrixd(glmat); + + m_pGL->glColor3f(0.,0.,0.); + m_pGL->glBegin(GL_LINE_STRIP); + m_pGL->glVertex3f(-0.5, 0., 0.); + m_pGL->glVertex3f(0.5, 0., 0.); + m_pGL->glVertex3f(0., 0.5, 0.); + m_pGL->glVertex3f(-0.5, 0., 0.); + m_pGL->glEnd(); + + m_pGL->glPopMatrix(); + } +}; + + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + + QDialog dlg; + GlWidget *pGl = new GlWidget(&dlg); + dlg.resize(800, 600); + + QGridLayout *pGrid = new QGridLayout(&dlg); + pGrid->addWidget(pGl, 0,0,1,1); + dlg.exec(); + + return 0; +} + +#include "tst_quat2.moc" diff --git a/tools/test/tst_refl.cpp b/tools/test/tst_refl.cpp new file mode 100644 index 0000000..57f113a --- /dev/null +++ b/tools/test/tst_refl.cpp @@ -0,0 +1,44 @@ +// gcc -DNO_QT -I. -I../.. -o tst_refl tst_refl.cpp ../../libs/spacegroups/spacegroup_clp.cpp ../../libs/spacegroups/crystalsys.cpp ../../tlibs/log/log.cpp -lstdc++ -std=c++11 -lclipper-core -lm + +#include +#include "libs/spacegroups/spacegroup_clp.h" + +void check_allowed_refls() +{ + const int HKL_MAX = 10; + unsigned int iSG = 0; + + const t_mapSpaceGroups *pSGs = get_space_groups(); + for(const t_mapSpaceGroups::value_type& sg : *pSGs) + { + ++iSG; + //if(iSG < 200) continue; + + const std::string& strName = sg.second.GetName(); + std::cout << "Checking (" << iSG << ") " << strName << " ... "; + + for(int i=-HKL_MAX; i<=HKL_MAX; ++i) + for(int j=-HKL_MAX; j<=HKL_MAX; ++j) + for(int k=-HKL_MAX; k<=HKL_MAX; ++k) + { + //std::cout << "(" << i << j << k << "): " << + // std::boolalpha << sg.second.HasReflection(i,j,k) << std::endl; + + if(sg.second.HasReflection(i,j,k) != sg.second.HasReflection2(i,j,k)) + { + std::cout << "Failed at " << i << " " << j << " " << k << std::endl; + return; + } + } + + std::cout << "OK" << std::endl; + } +} + +int main() +{ + init_space_groups(); + check_allowed_refls(); + + return 0; +} diff --git a/tools/test/tst_str.cpp b/tools/test/tst_str.cpp new file mode 100644 index 0000000..2c572fa --- /dev/null +++ b/tools/test/tst_str.cpp @@ -0,0 +1,12 @@ +// gcc -I../.. -o tst_str tst_str.cpp -std=c++11 -lstdc++ + +#include +#include "tlibs/string/string.h" + +int main() +{ + std::string strFile = "/home/tw/test.txt"; + + std::cout << tl::get_file_noext(tl::get_file(strFile)) << std::endl; + return 0; +} diff --git a/tools/test/tst_tof.cpp b/tools/test/tst_tof.cpp new file mode 100644 index 0000000..53685f8 --- /dev/null +++ b/tools/test/tst_tof.cpp @@ -0,0 +1,39 @@ +// gcc -DNO_QT -I. -I../.. -o tst_tof ../../tools/test/tst_tof.cpp ../../tools/res/viol.cpp ../../tlibs/log/log.cpp -lstdc++ -std=c++11 -lstdc++ -lm + +#include "tools/res/viol.h" +#include + +int main() +{ + ViolParams parms; + + parms.ki = 1.4 / tl::get_one_angstrom(); + parms.kf = 1.4 / tl::get_one_angstrom(); + //parms.E = 0. * tl::get_one_meV(); + + parms.len_pulse_mono = 10. * tl::get_one_meter(); + parms.len_mono_sample = 1. * tl::get_one_meter(); + parms.len_sample_det = 5. * tl::get_one_meter(); + + parms.twotheta = tl::d2r(75.) * tl::get_one_radian(); + parms.twotheta_i = 0. * tl::get_one_radian(); + parms.angle_outplane_i = 0. * tl::get_one_radian(); + parms.angle_outplane_f = 0. * tl::get_one_radian(); + + parms.sig_len_pulse_mono = 0.01 * tl::get_one_meter(); + parms.sig_len_mono_sample = 0.01 * tl::get_one_meter(); + parms.sig_len_sample_det = 0.01 * tl::get_one_meter(); + + parms.sig_pulse = 50e-6 * tl::get_one_second(); + parms.sig_mono = 5e-6 * tl::get_one_second(); + parms.sig_det = 5e-6 * tl::get_one_second(); + + parms.sig_twotheta_i = tl::m2r(30.) * tl::get_one_radian(); + parms.sig_twotheta_f = tl::m2r(30.) * tl::get_one_radian(); + parms.sig_outplane_i = tl::m2r(30.) * tl::get_one_radian(); + parms.sig_outplane_f = tl::m2r(30.) * tl::get_one_radian(); + + ResoResults res = calc_viol(parms); + + return 0; +} diff --git a/tools/test/tst_traits.cpp b/tools/test/tst_traits.cpp new file mode 100644 index 0000000..cc3e15f --- /dev/null +++ b/tools/test/tst_traits.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include "tlibs/math/linalg.h" +#include "tlibs/helper/traits.h" + +using namespace tl; + +int main() +{ + std::cout << "vec: " << get_type_dim>::value << std::endl; + std::cout << "ublas vec: " << get_type_dim>::value << std::endl; + std::cout << "ublas mat: " << get_type_dim>::value << std::endl; + std::cout << "map: " << get_type_dim>::value << std::endl; + + + std::cout << "vec: " << int(get_linalg_type>::value) << std::endl; + std::cout << "mat: " << int(get_linalg_type>::value) << std::endl; + return 0; +} diff --git a/ui/about.ui b/ui/about.ui new file mode 100644 index 0000000..da1e50a --- /dev/null +++ b/ui/about.ui @@ -0,0 +1,243 @@ + + + AboutDlg + + + + 0 + 0 + 438 + 364 + + + + About Takin + + + true + + + + + + 0 + + + + Version + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Built with cc + + + true + + + + + + + 2014 - 2015 + + + + + + + Written by Tobias Weber + + + + + + + Inelastic Neutron Scattering Software Package + + + true + + + + + + + Build date: + + + + + + + Version 1 + + + + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">Takin</span></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + License + + + + + + <html><head/><body><p>Takin is free software: you can redistribute it and/or modify it under the terms of the <span style=" font-weight:600;">GNU General Public License version 2</span> as published by the Free Software Foundation.</p><p>Takin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p><p>You should have received a copy of the GNU General Public License along with Takin. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p><br/></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + Libraries + + + + + + Libraries + + + true + + + + + + + + Tables + + + + + + Constants + + + true + + + + + + + + 3rd Party Licenses + + + + + + QPlainTextEdit::NoWrap + + + true + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + tabWidget + buttonBox + + + + + buttonBox + accepted() + AboutDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/atoms.ui b/ui/atoms.ui new file mode 100644 index 0000000..280fdb5 --- /dev/null +++ b/ui/atoms.ui @@ -0,0 +1,138 @@ + + + AtomsDlg + + + + 0 + 0 + 441 + 344 + + + + Atom Positions + + + true + + + + + + Add Atom + + + + + + + + + + Remove Atom + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + + Atom + + + + + x (frac) + + + + + y (frac) + + + + + z (frac) + + + + + + + + tableAtoms + btnAdd + btnDel + buttonBox + + + + + buttonBox + accepted() + AtomsDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AtomsDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/connection.ui b/ui/connection.ui new file mode 100644 index 0000000..e4228dd --- /dev/null +++ b/ui/connection.ui @@ -0,0 +1,174 @@ + + + SrvDlg + + + + 0 + 0 + 277 + 299 + + + + Connection + + + true + + + + + + Connection + + + + + + System: + + + + + + + + NICOS + + + + + SICS + + + + + + + + Host: + + + + + + + mira1.mira.frm2 + + + + + + + Port: + + + + + + + 14869 + + + + + + + + + + Login + + + + + + Login: + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Remember Password + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + comboSys + editHost + editPort + editLogin + editPwd + checkRememberPwd + buttonBox + + + + + buttonBox + accepted() + SrvDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SrvDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/disp.ui b/ui/disp.ui new file mode 100644 index 0000000..a47011d --- /dev/null +++ b/ui/disp.ui @@ -0,0 +1,593 @@ + + + DispDlg + + + + 0 + 0 + 443 + 499 + + + + Dispersion Relations + + + true + + + + + + + 2 + 0 + + + + Sample Unit Cell + + + + 4 + + + 2 + + + 4 + + + + + a (Å): + + + + + + + 5 + + + + + + + α (°): + + + + + + + 90 + + + + + + + b (Å): + + + + + + + 5 + + + + + + + β (°): + + + + + + + 90 + + + + + + + c (Å): + + + + + + + 5 + + + + + + + γ (°): + + + + + + + 90 + + + + + + + + + + + 1 + 0 + + + + Space Group + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + + <not set> + + + + + + + + + 0 + 0 + + + + Filter: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + System: + + + + + + + true + + + + + + + + + + + 2 + 0 + + + + Neighbours + + + + 4 + + + 2 + + + 4 + + + + + Centre: + + + + + + + Supercell: + + + + + + + + 1 + 0 + + + + Size of Super Cell + + + N = + + + 2 + + + + + + + Nearest: + + + + + + + + 1 + 0 + + + + Number of nearest neighbours + + + n = + + + 2 + + + + + + + + 1 + 0 + + + + Index of Centre Atom + + + + + + + ε Shell (Å): + + + + + + + + 1 + 0 + + + + Size of the Epsilon Shell for Nearest Neighbours + + + 0.01 + + + + + + + + + + + 1 + 0 + + + + Unit Cell + + + + 4 + + + 2 + + + 4 + + + + + Atom Positions... + + + + + + + Spin: + + + + + + + 0.5 + + + + + + + + + + 0 + + + + Neighbours + + + + 8 + + + + + true + + + true + + + false + + + false + + + + Order + + + + + Atom + + + + + x (Å) + + + + + y (Å) + + + + + z (Å) + + + + + Dist. (Å) + + + + + + + + + Ferromagnetic + + + + 8 + + + + + + 3 + 0 + + + + + + + + + + + + + 0 + + + + + + 1 + 0 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 0 + 0 + + + + Save... + + + + + + + + 0 + 0 + + + + Load... + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + editA + editB + editC + editAlpha + editBeta + editGamma + comboSpaceGroups + editSpaceGroupsFilter + editCrystalSystem + spinNN + spinCentreIdx + spinSC + editEpsShell + btnAtoms + editS + tabWidget + tableNN + btnSave + btnLoad + buttonBox + + + + + buttonBox + accepted() + DispDlg + accept() + + + 424 + 455 + + + 224 + 238 + + + + + buttonBox + rejected() + DispDlg + reject() + + + 424 + 455 + + + 224 + 238 + + + + +
diff --git a/ui/dw.ui b/ui/dw.ui new file mode 100644 index 0000000..7f2607d --- /dev/null +++ b/ui/dw.ui @@ -0,0 +1,586 @@ + + + DWDlg + + + + 0 + 0 + 478 + 520 + + + + Scattering Factors + + + true + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + 0 + + + + Bose Factor + + + + + + Temperature (K): + + + + + + + 2 + + + 9999.000000000000000 + + + 0.100000000000000 + + + 10.000000000000000 + + + + + + + Energy Range (meV): + + + + + + + 0.000000000000000 + + + 9999.000000000000000 + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + 9999.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + + + + + + Debye-Waller Factor + + + + + + + 1 + 0 + + + + Atomic Mass (amu): + + + + + + + + 1 + 0 + + + + Debye Temp. (K): + + + + + + + + 1 + 0 + + + + Temperature (K): + + + + + + + + 1 + 0 + + + + 9999.000000000000000 + + + 50.000000000000000 + + + + + + + + 1 + 0 + + + + 9999.000000000000000 + + + 0.100000000000000 + + + 50.000000000000000 + + + + + + + + 1 + 0 + + + + 9999.000000000000000 + + + 0.100000000000000 + + + 10.000000000000000 + + + + + + + + 1 + 0 + + + + Q Range (Å⁻¹): + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + 1 + 0 + + + + RMS Atom. Displ. (Å): + + + + + + + true + + + + 1 + 0 + + + + true + + + + + + + + 0 + 0 + + + + + + plot + spinAMU_deb + label_22 + spinT_deb + spinMinQ_deb + label_21 + editZetaSq + label_20 + label_24 + label_23 + spinMaxQ_deb + spinTD_deb + + + + Analyser Factor + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + 3.355000000000000 + + + + + + + + 1 + 0 + + + + kf Range (Å⁻¹): + + + + + + + Analyser d (Å): + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + 2.000000000000000 + + + + + + + + 0 + 0 + + + + + + + + Analyser Angle ϑ (deg): + + + + + + + true + + + + + + + true + + + + + + + + Lorentz Factor + + + + + + + 1 + 0 + + + + 4 + + + 360.000000000000000 + + + 0.100000000000000 + + + 90.000000000000000 + + + + + + + + 1 + 0 + + + + Scattering Angle 2ϑ Range (deg): + + + + + + + + 1 + 0 + + + + 4 + + + 360.000000000000000 + + + 0.100000000000000 + + + 45.000000000000000 + + + + + + + + 0 + 0 + + + + + + + + Include Polarisation (only relevant for X-Rays) + + + + + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + tabWidget + spinBoseT + spinBoseEMin + spinBoseEMax + spinAMU_deb + spinTD_deb + spinT_deb + spinMinQ_deb + spinMaxQ_deb + editZetaSq + spinAnad + spinMinkf + spinMaxkf + editAngMin + editAngMax + spinMin2Th + spinMax2Th + checkPol + buttonBox + + + + + buttonBox + accepted() + DWDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DWDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/dyn_plane.ui b/ui/dyn_plane.ui new file mode 100644 index 0000000..7da5e04 --- /dev/null +++ b/ui/dyn_plane.ui @@ -0,0 +1,265 @@ + + + DynPlaneDlg + + + + 0 + 0 + 438 + 434 + + + + Kinematic Plane + + + true + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + 1 + 0 + + + + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + + + + Sc. Type: + + + + + + + + Fixed E_i + + + + + Fixed E_f + + + + + + + + Sync + + + true + + + true + + + + + + + E_i (meV): + + + + + + + + 1 + 0 + + + + 4 + + + 99999.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + 2θ (deg): + + + + + + + + 1 + 0 + + + + 4 + + + 180.000000000000000 + + + 0.100000000000000 + + + + + + + Q Min (Å⁻¹): + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + + + + + Q Max (Å⁻¹): + + + + + + + + 1 + 0 + + + + 4 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + + + 0 + 0 + + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + comboFixedE + btnSync + spinEiEf + spinAngle + spinMinQ + spinMaxQ + buttonBox + + + + + buttonBox + accepted() + DynPlaneDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DynPlaneDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/ellipses.ui b/ui/ellipses.ui new file mode 100644 index 0000000..4675478 --- /dev/null +++ b/ui/ellipses.ui @@ -0,0 +1,209 @@ + + + EllipseDlg + + + + 0 + 0 + 600 + 521 + + + + Resolution Ellipses + + + true + + + + 4 + + + 4 + + + + + + 1 + 1 + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 4 + + + 4 + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + + + + Center Ellipses on Coordinate Origin + + + Center + + + true + + + + + + + + 0 + 0 + + + + + Q∥ Q⟂ System (Å⁻¹) + + + + + hkl System (rlu) + + + + + Scattering Plane System (rlu) + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + QFrame::Plain + + + + + + + + 1 + 1 + + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + checkCenter + comboCoord + buttonBox + + + + + buttonBox + accepted() + EllipseDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EllipseDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/formfactors.ui b/ui/formfactors.ui new file mode 100644 index 0000000..8753ac0 --- /dev/null +++ b/ui/formfactors.ui @@ -0,0 +1,519 @@ + + + FormFactorDlg + + + + 0 + 0 + 573 + 411 + + + + List of Elements + + + true + + + + + + 0 + + + + Neutron Scattering Lengths + + + + + + QTabWidget::West + + + QTabWidget::Triangular + + + 0 + + + + Table + + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + + 4 + + + 4 + + + + + Search: + + + + + + + + + + + + + + 3 + 0 + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + + No. + + + + + Nucleus + + + + + Re(Coh.) + + + + + Im(Coh.) + + + + + Re(Inc.) + + + + + Im(Inc.) + + + + + + + + Qt::Vertical + + + + 20 + 227 + + + + + + + + + Graph + + + + + + + 3 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 276 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + + 4 + + + 4 + + + + + Coherent + + + true + + + + + + + Incoherent + + + + + + + + + + + + + + + Magnetic Form Factors + + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + Atom / Ion + + + + 4 + + + 4 + + + + + + 0 + 0 + + + + L= + + + 1 + + + 0.500000000000000 + + + + + + + J= + + + 1 + + + 0.500000000000000 + + + + + + + + 0 + 0 + + + + S= + + + 1 + + + 0.500000000000000 + + + + + + + + 0 + 0 + + + + true + + + + + + + Term Sym.: + + + + + + + Search: + + + + + + + + 0 + 0 + + + + Search Atoms + + + + + + + Orbitals: + + + + + + + + 0 + 0 + + + + Orbitals + + + + + + + + + 3 + 0 + + + + + + + + + + X-Ray Form Factors + + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + 0 + 0 + + + + Atom / Ion + + + + 4 + + + 4 + + + + + Search Atoms + + + + + + + false + + + true + + + + + + + + + 3 + 0 + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + tabWidget + tabSc2 + editSLSearch + tableSL + radioCoherent + radioIncoherent + listMAtoms + spinJ + spinL + spinS + listAtoms + editFilter + buttonBox + + + + + buttonBox + accepted() + FormFactorDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FormFactorDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/goto.ui b/ui/goto.ui new file mode 100644 index 0000000..29eccb7 --- /dev/null +++ b/ui/goto.ui @@ -0,0 +1,487 @@ + + + GotoDlg + + + + 0 + 0 + 691 + 354 + + + + Go to Position + + + true + + + + + + Qt::Horizontal + + + + + QLayout::SetDefaultConstraint + + + + + Add Current Position + + + + + + + + + + Remove Position + + + + + + + + + + Save Positions... + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Load Positions... + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + QAbstractItemView::InternalMove + + + true + + + false + + + + + + + + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 0 + 0 + + + + QFrame::Panel + + + QFrame::Sunken + + + + + + + + + + + 0 + 0 + + + + Reciprocal Space + + + + + + k_f (Å⁻¹): + + + + + + + k_i (Å⁻¹): + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + + + + + l (rlu): + + + + + + + h (rlu): + + + + + + + k (rlu): + + + + + + + + + + ΔE (meV): + + + + + + + + + + Fixed k_i + + + true + + + + + + + Fixed k_f + + + + + + + + + + + 0 + 0 + + + + Real Space + + + + + + false + + + + + + + θ_M (deg): + + + + + + + 2θ_A (deg): + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + true + + + + + + + θ_A (deg): + + + + + + + true + + + + + + + θ_S (deg): + + + + + + + 2θ_M (deg): + + + + + + + Qt::Horizontal + + + + + + + 2θ_S (deg): + + + + + + + Qt::Horizontal + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Get Current Position + + + Get Position + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + editH + editK + editL + editKi + editKf + editE + radioFixedKi + radioFixedKf + edit2ThetaM + editThetaM + edit2ThetaS + editThetaS + edit2ThetaA + editThetaA + btnAdd + btnDel + btnSave + btnLoad + btnGetPos + buttonBox + listSeq + + + + + buttonBox + rejected() + GotoDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + GotoDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/ui/monteconvo.ui b/ui/monteconvo.ui new file mode 100644 index 0000000..50c7ae5 --- /dev/null +++ b/ui/monteconvo.ui @@ -0,0 +1,1198 @@ + + + ConvoDlg + + + + 0 + 0 + 443 + 487 + + + + Convolution + + + true + + + + 8 + + + 6 + + + + + + 0 + 0 + + + + 0 + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + 0 + 0 + + + + Start + + + + + + + 0 + + + + Settings + + + + 4 + + + + + Scan Steps in (hkl) [rlu], E [meV] + + + + 4 + + + 2 + + + 4 + + + + + + 1 + 0 + + + + k (rlu) + + + k = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 4.200000000000000 + + + + + + + + 0 + 0 + + + + To: + + + + + + + + 1 + 0 + + + + l (rlu) + + + l = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + + 1 + 0 + + + + E (meV) + + + E = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + + 1 + 0 + + + + l (rlu) + + + l = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + + 1 + 0 + + + + E (meV) + + + E = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 10.000000000000000 + + + + + + + + 1 + 0 + + + + h (rlu) + + + h = + + + + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 3.800000000000000 + + + + + + + + 1 + 0 + + + + h (rlu) + + + h = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 3.800000000000000 + + + + + + + + 1 + 0 + + + + k (rlu) + + + k = + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 4.200000000000000 + + + + + + + + 0 + 0 + + + + From: + + + + + + + + 1 + 0 + + + + 1 + + + 16384 + + + 64 + + + + + + + + 0 + 0 + + + + Steps: + + + + + + + + + + Configuration + + + + 4 + + + 2 + + + 4 + + + + + + None + + + + + Horizontal + + + + + Vertical + + + + + Both + + + + + + + + + None + + + + + Horizontal + + + + + Vertical + + + + + Both + + + + + + + + 1 + + + + Cooper-Nathans + + + + + Popovici + + + + + Eckold-Sobolev + + + + + + + + + 0 + 0 + + + + Neutrons: + + + + + + + k_fix (1/Å): + + + + + + + 1 + + + + ki = const. + + + + + kf = const. + + + + + + + + + 0 + 0 + + + + 1 + + + 999999999 + + + 1000 + + + 1000 + + + + + + + + 0 + 0 + + + + 6 + + + 0.001000000000000 + + + 2.662000000000000 + + + + + + + + 0 + 0 + + + + Algorithm: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + Mode: + + + + + + + M. Focus: + + + + + + + A. Focus: + + + + + + + + + + Dynamical Structure Factor S(Q,ω) + + + + 4 + + + 2 + + + 4 + + + + + Model Source: + + + + + + + + 0 + 0 + + + + + + + + File: + + + + + + + + + + + 0 + 0 + + + + Browse for S(q,w) files + + + ... + + + + + + + + 0 + 0 + + + + Parameters... + + + ... + + + + + + + + + + Configuration Files + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + Browse for resolution files + + + ... + + + + + + + + + + + 0 + 0 + + + + Browse for crystal files + + + ... + + + + + + + Crystal File: + + + + + + + Resolution File: + + + + + + + + + + Measurement: + + + + + + + false + + + + + + + false + + + + 0 + 0 + + + + ... + + + + + + + + + + + Results + + + + 4 + + + + + + 0 + 0 + + + + + DejaVu Sans Mono + + + + false + + + QPlainTextEdit::NoWrap + + + true + + + + + + + + + + Qt::Horizontal + + + + 348 + 20 + + + + + + + + + 0 + 0 + + + + Save... + + + + + + + + Plot + + + + 4 + + + 6 + + + + + + 0 + 0 + + + + + + + + Scale: + + + + + + + 1 + + + + + + + Offset: + + + + + + + 0 + + + + + + + + + + + false + + + + 0 + 0 + + + + Stop + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + tabWidget + editCrys + btnBrowseCrys + editRes + btnBrowseRes + checkScan + editScan + btnBrowseScan + comboAlgo + spinNeutrons + comboFixedK + spinKfix + comboFocMono + comboFocAna + comboSqw + btnSqwParams + editSqw + btnBrowseSqw + spinStartH + spinStartK + spinStartL + spinStartE + spinStopH + spinStopK + spinStopL + spinStopE + spinStepCnt + textResult + editScale + editOffs + btnStart + btnStop + buttonBox + btnSaveResult + + + + + buttonBox + accepted() + ConvoDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ConvoDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + checkScan + toggled(bool) + editScan + setEnabled(bool) + + + 80 + 122 + + + 282 + 122 + + + + + checkScan + toggled(bool) + btnBrowseScan + setEnabled(bool) + + + 80 + 122 + + + 441 + 122 + + + + + checkScan + toggled(bool) + editCrys + setDisabled(bool) + + + 80 + 122 + + + 282 + 70 + + + + + checkScan + toggled(bool) + btnBrowseCrys + setDisabled(bool) + + + 80 + 122 + + + 441 + 70 + + + + + checkScan + toggled(bool) + spinStartH + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStartK + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStartL + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStartE + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStopH + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStopK + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStopL + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + checkScan + toggled(bool) + spinStopE + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/ui/netcache.ui b/ui/netcache.ui new file mode 100644 index 0000000..6127310 --- /dev/null +++ b/ui/netcache.ui @@ -0,0 +1,83 @@ + + + NetCacheDlg + + + + 0 + 0 + 731 + 463 + + + + Network Cache + + + true + + + + 8 + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + true + + + true + + + false + + + + + + + + + buttonBox + accepted() + NetCacheDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NetCacheDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/neutrons.ui b/ui/neutrons.ui new file mode 100644 index 0000000..7743c38 --- /dev/null +++ b/ui/neutrons.ui @@ -0,0 +1,507 @@ + + + NeutronDlg + + + + 0 + 0 + 421 + 467 + + + + Basic Neutron Properties + + + true + + + + + + Calculator: + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + 0 + + + + Neutron Properties + + + + + + + 0 + 0 + + + + Velocity v (m/s): + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Wavelength λ (Å): + + + + + + + 5 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Wavenumber k (Å⁻¹): + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Energy E (meV): + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Frequency ω (THz): + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Temperature T (K): + + + + + + + Frequency f (THz): + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + Bragg Scattering + + + + + + Real + + + + + + 1 + + + + + + + 5 + + + + + + + 3 + + + + + + + true + + + + + + + λ (Å): + + + + + + + d (Å): + + + + + + + θ, 2θ (deg): + + + true + + + + + + + n: + + + + + + + true + + + + + + + + + + Reciprocal + + + + + + 1 + + + + + + + 5 + + + + + + + 0.5 + + + + + + + true + + + + + + + λ (Å): + + + + + + + Q (Å⁻¹): + + + + + + + θ, 2θ (deg): + + + true + + + + + + + n: + + + + + + + true + + + + + + + + + + + Constants + + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + + Variable + + + + + Name + + + + + CODATA Value + + + + + + + + + Conversions + + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + + Conversion + + + + + Factor + + + + + + + + + + + + + + + tabWidget + editLam + editK + editE + editOm + editF + editT + editV + radioBraggDirLam + radioBraggDirD + radioBraggDirTT + editBraggDirN + editBraggDirLam + editBraggDirD + editBraggDirT + editBraggDirTT + radioBraggReciLam + radioBraggReciQ + radioBraggReciTT + editBraggReciN + editBraggReciLam + editBraggReciQ + editBraggReciT + editBraggReciTT + tableConst + tableConv + buttonBox + + + + + buttonBox + accepted() + NeutronDlg + accept() + + + 257 + 457 + + + 157 + 274 + + + + + buttonBox + rejected() + NeutronDlg + reject() + + + 325 + 457 + + + 286 + 274 + + + + + diff --git a/ui/powder.ui b/ui/powder.ui new file mode 100644 index 0000000..cd9119b --- /dev/null +++ b/ui/powder.ui @@ -0,0 +1,614 @@ + + + PowderDlg + + + + 0 + 0 + 514 + 475 + + + + Powder Lines + + + true + + + + 8 + + + + + + 1 + 0 + + + + Space Group + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + + <not set> + + + + + + + + + 0 + 0 + + + + Filter: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + System: + + + + + + + true + + + + + + + + + + + 1 + 0 + + + + Unit Cell + + + + 4 + + + 2 + + + 4 + + + + + Atom Positions... + + + + + + + + + + + 2 + 0 + + + + Input Parameters + + + + 4 + + + 2 + + + 4 + + + + + Wavelength: + + + + + + + + 1 + 0 + + + + n = + + + 1 + + + 5 + + + + + + + + 2 + 0 + + + + λ = + + + + + + 4 + + + 9999.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + + 0 + 0 + + + + Unique + + + true + + + + + + + + + + + 1 + 1 + + + + Elastic Reflexes + + + false + + + + 0 + + + 2 + + + 0 + + + 0 + + + 2 + + + + + 0 + + + + Table + + + + 8 + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + false + + + + 2θ (deg) + + + + + Q (Å⁻¹) + + + + + Peak + + + + + Mult. + + + + + |F_n| (fm) + + + + + S_n (fm²) + + + + + |F_xray| (e-) + + + + + S_xray + + + + + + + + + Neutron Diffraction Pattern + + + + 8 + + + + + + 3 + 0 + + + + + + + + + X-Ray Diffraction Pattern + + + + 8 + + + + + + 3 + 0 + + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + 2 + 0 + + + + Sample Unit Cell + + + + 4 + + + 2 + + + 4 + + + + + a (Å): + + + + + + + 5 + + + + + + + α (°): + + + + + + + 90 + + + + + + + b (Å): + + + + + + + 5 + + + + + + + β (°): + + + + + + + 90 + + + + + + + c (Å): + + + + + + + 5 + + + + + + + γ (°): + + + + + + + 90 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Save... + + + + + + + + 0 + 0 + + + + Load... + + + + + + + + 0 + 0 + + + + Save Table... + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + editA + editB + editC + editAlpha + editBeta + editGamma + comboSpaceGroups + editSpaceGroupsFilter + editCrystalSystem + spinLam + spinOrder + checkUniquePeaks + btnAtoms + tabWidget + tablePowderLines + btnSaveTable + btnSave + btnLoad + buttonBox + + + + + buttonBox + accepted() + PowderDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PowderDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/real_params.ui b/ui/real_params.ui new file mode 100644 index 0000000..2495719 --- /dev/null +++ b/ui/real_params.ui @@ -0,0 +1,347 @@ + + + RealParamDlg + + + + 0 + 0 + 535 + 366 + + + + Real Space Info + + + true + + + + 8 + + + + + 0 + + + + Unit Cell + + + + 4 + + + + + Qt::Horizontal + + + 4 + + + + + 1 + 0 + + + + Unit Cell + + + true + + + + + + 1 + 0 + + + + Super Cell + + + true + + + + Neighbours + + + + + Rel. Position + + + + + + + + + + Instrument + + + + 4 + + + + + Angles + + + + 4 + + + 2 + + + + + true + + + + + + + θ_S (deg): + + + + + + + 2θ_A (deg): + + + + + + + true + + + + + + + 2θ_S (deg): + + + + + + + 2θ_M (deg): + + + + + + + θ_M (deg): + + + + + + + true + + + + + + + true + + + + + + + θ_A (deg): + + + + + + + true + + + + + + + true + + + + + + + + + + Lengths + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + Sample → Analyser (cm): + + + + + + + true + + + + + + + + 0 + 0 + + + + Monochromator → Sample (cm): + + + + + + + true + + + + + + + true + + + + + + + + 0 + 0 + + + + Analyser → Detector (cm): + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + tabWidget + editLenMonoSample + editLenSampleAna + editLenAnaDet + edit2ThetaM + editThetaM + edit2ThetaS + editThetaS + edit2ThetaA + editThetaA + listAtoms + treeNN + buttonBox + + + + + buttonBox + accepted() + RealParamDlg + accept() + + + 227 + 493 + + + 157 + 274 + + + + + buttonBox + rejected() + RealParamDlg + reject() + + + 295 + 499 + + + 286 + 274 + + + + + diff --git a/ui/recip_params.ui b/ui/recip_params.ui new file mode 100644 index 0000000..5d55720 --- /dev/null +++ b/ui/recip_params.ui @@ -0,0 +1,877 @@ + + + RecipParamDlg + + + + 0 + 0 + 634 + 443 + + + + Reciprocal Space Info + + + true + + + + 8 + + + + + 0 + + + + Parameters + + + + + + Initial Values + + + + 4 + + + 2 + + + + + k_i (Å⁻¹): + + + + + + + true + + + + + + + E_i (meV): + + + + + + + true + + + + + + + λ_i (Å): + + + + + + + true + + + + + + + v_i (m/s): + + + + + + + true + + + + + + + + + + Final Values + + + + 4 + + + 2 + + + + + k_f (Å⁻¹): + + + + + + + true + + + + + + + E_f (meV): + + + + + + + true + + + + + + + λ_f (Å): + + + + + + + true + + + + + + + v_f (m/s): + + + + + + + true + + + + + + + + + + Transfers + + + + 4 + + + 2 + + + + + true + + + + + + + Q (Å⁻¹): + + + + + + + true + + + + + + + ΔE (meV): + + + + + + + q (Å⁻¹): + + + + + + + true + + + + + + + true + + + + + + + q (rlu): + + + + + + + + + + Angles + + + + 4 + + + 2 + + + + + kfQ (deg): + + + + + + + true + + + + + + + true + + + + + + + kiQ (deg): + + + + + + + true + + + + + + + 2θ (deg): + + + + + + + θ (deg): + + + + + + + true + + + + + + + + + + Scattering Vector + + + + 4 + + + 2 + + + + + true + + + + + + + true + + + + + + + Q (Å⁻¹): + + + + + + + true + + + + + + + Q (rlu): + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + Reduced Scattering Vector + + + + 4 + + + 2 + + + + + true + + + + + + + true + + + + + + + q (Å⁻¹): + + + + + + + true + + + + + + + q (rlu): + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + Lattice Vector + + + + 4 + + + 2 + + + + + true + + + + + + + true + + + + + + + G (Å⁻¹): + + + + + + + true + + + + + + + G (rlu): + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + Transverse Focusing Direction + + + + 4 + + + 2 + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + (for -E) + + + + + + + (for +E) + + + + + + + F+ (rlu): + + + + + + + F- (rlu): + + + + + + + + + + + Definitions for Measurement + + + + + + + 0 + 0 + + + + Origin Vector + + + + 4 + + + 2 + + + + + 0 + + + false + + + + + + + 0 + + + false + + + + + + + 1 + + + false + + + + + + + Q (rlu): + + + + + + + Use G Vector + + + + + + + + + + + 0 + 0 + + + + Scan Direction (for Focus) + + + + 4 + + + 2 + + + + + +E Direction + + + true + + + + + + + -E Direction + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 1 + 0 + + + + Definitions + + + + 4 + + + 2 + + + + + false + + + QTextEdit::NoWrap + + + true + + + false + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + tabWidget + editKi + editEi + editLami + editVi + editKf + editEf + editLamf + editVf + editE + editQ + editq + editqrlu + edit2Theta + editTheta + editKiQ + editKfQ + editQx + editQy + editQz + editQxrlu + editQyrlu + editQzrlu + editqx + editqy + editqz + editqxrlu + editqyrlu + editqzrlu + editGx + editGy + editGz + editGxrlu + editGyrlu + editGzrlu + editFpx + editFpy + editFpz + editFmx + editFmy + editFmz + editOriginH + editOriginK + editOriginL + btnUseG + radioEp + radioEm + editDefs + buttonBox + + + + + buttonBox + accepted() + RecipParamDlg + accept() + + + 227 + 493 + + + 157 + 274 + + + + + buttonBox + rejected() + RecipParamDlg + reject() + + + 295 + 499 + + + 286 + 274 + + + + + diff --git a/ui/reso.ui b/ui/reso.ui new file mode 100644 index 0000000..f6753bf --- /dev/null +++ b/ui/reso.ui @@ -0,0 +1,3105 @@ + + + ResoDlg + + + + 0 + 0 + 752 + 406 + + + + TAS/TOF Resolution Parameters + + + true + + + + 8 + + + + + Load... + + + + + + + Save... + + + + + + + + 1 + 0 + + + + QFrame::Panel + + + QFrame::Sunken + + + Ready. + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + 5 + + + + TAS + + + + + + + 0 + 0 + + + + Horizontal Collimation + + + + 2 + + + 2 + + + 4 + + + + + Before Mono: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 30.000000000000000 + + + + + + + Before Sample: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 30.000000000000000 + + + + + + + After Sample: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 30.000000000000000 + + + + + + + After Analyser: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 30.000000000000000 + + + + + + + + + + + 0 + 0 + + + + Analyser + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + d-spacing: + + + + + + + + + + 5 + + + 0.010000000000000 + + + 3.355000000000000 + + + + + + + Mosaic: + + + + + + + arcmin + + + 4 + + + 999.000000000000000 + + + 50.000000000000000 + + + + + + + Positive scattering sense + + + false + + + + + + + Negative scattering sense + + + true + + + + + + + Efficiency: + + + + + + + 4 + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + + + + 0 + 0 + + + + Vertical Collimation + + + + 2 + + + 2 + + + 4 + + + + + Before Mono: + + + + + + + arcmin + + + 9999.000000000000000 + + + 9999.000000000000000 + + + + + + + Before Sample: + + + + + + + arcmin + + + 9999.000000000000000 + + + 9999.000000000000000 + + + + + + + After Sample: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 9999.000000000000000 + + + + + + + After Analyser: + + + + + + + arcmin + + + 99990000.000000000000000 + + + 9999.000000000000000 + + + + + + + + + + + 0 + 0 + + + + Sample + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + Mosaic: + + + + + + + arcmin + + + 4 + + + 999.000000000000000 + + + 50.000000000000000 + + + + + + + Positive scattering sense + + + true + + + + + + + Negative scattering sense + + + + + + + + + + + 0 + 0 + + + + Monochromator + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + d-spacing: + + + + + + + + + + 5 + + + 0.010000000000000 + + + 3.355000000000000 + + + + + + + Mosaic: + + + + + + + arcmin + + + 4 + + + 999.000000000000000 + + + 50.000000000000000 + + + + + + + Positive scattering sense + + + false + + + + + + + Negative scattering sense + + + true + + + + + + + Reflectivity: + + + + + + + 4 + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + TAS Geometry + + + + + + Analyser + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + Width: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Height: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Thickness: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + 0 + 0 + + + + + Flat Horiz. Curv. + + + + + Opt. Horiz. Curv. + + + + + Horiz. Curv.: + + + + + + + + false + + + cm + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + + Flat Vert. Curv. + + + + + Opt. Vert. Curv. + + + + + Vert. Curv.: + + + + + + + + false + + + cm + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Dist. to Detector: + + + + + + + cm + + + 4 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 2.000000000000000 + + + + + + + + + + true + + + Guide + + + true + + + true + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + true + + + Horiz. div.: + + + + + + + true + + + arcmin/Å + + + 99999.000000000000000 + + + + + + + true + + + Vert. div.: + + + + + + + true + + + arcmin/Å + + + 99999.000000000000000 + + + + + + + + + + Detector + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + Rectangular + + + true + + + + + + + Width: + + + + + + + cm + + + 4 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Height: + + + + + + + cm + + + 4 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Circular + + + + + + + + + + Monochromator + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + Width: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Height: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Thickness: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + 0 + 0 + + + + + Flat Horiz. Curv. + + + + + Opt. Horiz. Curv. + + + + + Horiz. Curv.: + + + + + + + + false + + + cm + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.010000000000000 + + + + + + + + 0 + 0 + + + + + Flat Vert. Curv. + + + + + Opt. Vert. Curv. + + + + + Vert. Curv.: + + + + + + + + false + + + cm + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 0.010000000000000 + + + + + + + + 0 + 0 + + + + Dist. to Sample: + + + + + + + cm + + + 4 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 5.000000000000000 + + + + + + + + + + Source + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + Rectangular + + + true + + + + + + + Width: + + + + + + + cm + + + 4 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Height: + + + + + + + cm + + + 4 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Dist. to Mono: + + + + + + + cm + + + 4 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 2.000000000000000 + + + + + + + Circular + + + + + + + + + + Sample + + + + 2 + + + 2 + + + 4 + + + + + Cuboid + + + true + + + + + + + Cylindrical + + + + + + + Width along Q: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Width perp. Q: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Height: + + + + + + + cm + + + 5 + + + 999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Dist. to Ana.: + + + + + + + cm + + + 4 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 5.000000000000000 + + + + + + + + + + + Advanced TAS + + + + + + + 0 + 0 + + + + Analyser + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + arcmin + + + 4 + + + 999.000000000000000 + + + 50.000000000000000 + + + + + + + Vertical Mosaic: + + + + + + + + + + Sample + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + x Position: + + + + + + + cm + + + 5 + + + -999.000000000000000 + + + 999.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + + y Position: + + + + + + + cm + + + 5 + + + -999.000000000000000 + + + 999.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + + z Position: + + + + + + + cm + + + 5 + + + -999.000000000000000 + + + 999.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + + + + + + 0 + 0 + + + + Monochromator + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + arcmin + + + 4 + + + 999.000000000000000 + + + 50.000000000000000 + + + + + + + Vertical Mosaic: + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + TOF + + + + + + Distances + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + Pulse to Mono.: + + + + + + + cm + + + 2 + + + 99999999.000000000000000 + + + 1.000000000000000 + + + 1000.000000000000000 + + + + + + + Mono. to Sample: + + + + + + + cm + + + 2 + + + 99999999.000000000000000 + + + 1.000000000000000 + + + 100.000000000000000 + + + + + + + Sample to Det.: + + + + + + + cm + + + 2 + + + 99999999.000000000000000 + + + 1.000000000000000 + + + 500.000000000000000 + + + + + + + + + + Divergences + + + + 2 + + + 2 + + + 4 + + + + + Pulse to Mono.: + + + + + + + cm + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Mono. to Sample: + + + + + + + cm + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Sample to Det.: + + + + + + + cm + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + + Angles + + + + 2 + + + 2 + + + 4 + + + + + Incident 2θ: + + + + + + + + + + deg + + + 4 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + Incident φ: + + + + + + + + + + deg + + + 4 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + + + + deg + + + 4 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + Final φ: + + + + + + + + + + Time Bases + + + + 2 + + + 2 + + + 4 + + + + + Pulse: + + + + + + + Δt = + + + μs + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 50.000000000000000 + + + + + + + Mono.: + + + + + + + Δt = + + + μs + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Detector: + + + + + + + Δt = + + + μs + + + 4 + + + 999999.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Detector + + + + 4 + + + + + Spherical + + + true + + + + + + + Cylindrical + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Angular Acceptances + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + Incident 2θ: + + + + + + + + + + deg + + + 6 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + Final 2θ: + + + + + + + + + + deg + + + 6 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + Incident φ: + + + + + + + + + + deg + + + 6 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + Final φ: + + + + + + + + + + deg + + + 6 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + + + + Simple + + + + + + Deviation in k_i + + + + 2 + + + 2 + + + 4 + + + + + In Plane (para.): + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + In Plane (perp.): + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Out of Plane: + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + + + Deviation in k_f + + + + 2 + + + 2 + + + 4 + + + + + In Plane (para.): + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + In Plane (perp.): + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Out of Plane: + + + + + + + /Å + + + 4 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + + + Qt::Vertical + + + + 488 + 225 + + + + + + + + + Calculation + + + + + + + 0 + 0 + + + + Transfers + + + + 2 + + + 2 + + + 4 + + + + + k_i (Å⁻¹): + + + + + + + 1.4 + + + false + + + + + + + k_f (Å⁻¹): + + + + + + + 1.4 + + + false + + + + + + + Q (Å⁻¹): + + + + + + + 0.1 + + + false + + + + + + + E (meV): + + + + + + + 0 + + + true + + + + + + + + + + + 1 + 0 + + + + Results + + + + 4 + + + 2 + + + + + true + + + false + + + true + + + + + + + + + + + 0 + 0 + + + + Algorithm + + + + QFormLayout::AllNonFixedFieldsGrow + + + 2 + + + 2 + + + 4 + + + + + + + + Reference: + + + + + + + Ref + + + + + + + + + + + Monte-Carlo + + + + + + + 0 + 0 + + + + Monte-Carlo neutrons + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + Count: + + + + + + + + 0 + 0 + + + + 1 + + + 1000000 + + + 1000 + + + + + + + Generate... + + + + + + + Center around (0,0,0,0) + + + + + + + + 0 + 0 + + + + + Direct (Q∥ Q⟂) + + + + + Lattice (Å⁻¹) + + + + + Lattice (rlu) + + + + + + + + + 0 + 0 + + + + System: + + + + + + + + + + + 0 + 1 + + + + Command line for external simulation + + + true + + + + 4 + + + 2 + + + + + true + + + + + + + + + + + 1 + 1 + + + + Ellipsoid + + + + 4 + + + 2 + + + + + true + + + false + + + true + + + + + + + + + + Ellipsoid + + + + 4 + + + 2 + + + + + Calculate automatically + + + true + + + + + + + Calculate + + + + + + + + + + + + + + spinMonod + spinMonoMosaic + radioMonoScatterPlus + radioMonoScatterMinus + spinMonoRefl + spinSampleMosaic + radioSampleScatterPlus + radioSampleScatterMinus + spinAnad + spinAnaMosaic + radioAnaScatterPlus + radioAnaScatterMinus + spinAnaEffic + spinHCollMono + spinHCollBSample + spinHCollASample + spinHCollAna + spinVCollMono + spinVCollBSample + spinVCollASample + spinVCollAna + spinMonoW + spinMonoH + spinMonoThick + comboMonoHori + spinMonoCurvH + comboMonoVert + spinMonoCurvV + spinDistMonoSample + radioSampleCub + radioSampleCyl + spinSampleW_Q + spinSampleW_perpQ + spinSampleH + spinDistSampleAna + spinAnaW + spinAnaH + spinAnaThick + comboAnaHori + spinAnaCurvH + comboAnaVert + spinAnaCurvV + spinDistAnaDet + radioSrcRect + radioSrcCirc + spinSrcW + spinSrcH + spinDistSrcMono + groupGuide + spinGuideDivH + spinGuideDivV + radioDetRect + radioDetCirc + spinDetW + spinDetH + spinMonoMosaicV + spinSamplePosX + spinSamplePosY + spinSamplePosZ + spinAnaMosaicV + spinDistTofPulseMono + spinDistTofMonoSample + spinDistTofSampleDet + spinDistTofPulseMonoSig + spinDistTofMonoSampleSig + spinDistTofSampleDetSig + spinTofPulseSig + spinTofMonoSig + spinTofDetSig + spinTof2thI + spinTofphI + spinTofphF + spinTof2thISig + spinTof2thFSig + spinTofphISig + spinTofphFSig + editKi + editKf + editQ + editE + comboAlgo + editResults + checkElli4dAutoCalc + btnCalcElli4d + spinMCNeutrons + comboMCCoords + checkMCCenter + btnMCGenerate + editElli + groupSim + editSim + btnSave + btnLoad + buttonBox + tabWidget + + + + + buttonBox + accepted() + ResoDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ResoDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + groupSim + toggled(bool) + editSim + setEnabled(bool) + + + 494 + 311 + + + 494 + 317 + + + + + groupGuide + toggled(bool) + spinVCollMono + setDisabled(bool) + + + 401 + 326 + + + 510 + 286 + + + + + groupGuide + toggled(bool) + spinHCollMono + setDisabled(bool) + + + 401 + 326 + + + 231 + 286 + + + + + diff --git a/ui/scanviewer.ui b/ui/scanviewer.ui new file mode 100644 index 0000000..5e0db38 --- /dev/null +++ b/ui/scanviewer.ui @@ -0,0 +1,569 @@ + + + ScanViewerDlg + + + + 0 + 0 + 785 + 528 + + + + Scan Viewer + + + true + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + ... + + + + + + + + 2 + 1 + + + + false + + + true + + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 1 + 0 + + + + + + + + + 0 + 0 + + + + Axes: + + + + + + + + 1 + 0 + + + + + + + + 0 + + + + Plot + + + + + + + 4 + 1 + + + + + + + + + Experiment + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Scattering Plane + + + + + + x: + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + y: + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + + + + Experiment + + + + + + true + + + + + + + Contact: + + + + + + + User: + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 16 + 20 + + + + + + + + true + + + + + + + kfix (1/Å): + + + + + + + Title: + + + + + + + Sample: + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + Date: + + + + + + + + + + Sample + + + false + + + + + + c (Å): + + + + + + + b (Å): + + + + + + + true + + + + + + + a (Å): + + + + + + + true + + + + + + + true + + + + + + + γ (deg): + + + + + + + α (deg): + + + + + + + true + + + + + + + true + + + + + + + β (deg): + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 16 + 20 + + + + + + + + + + + + All Properties + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + + + + + + Export + + + + + + Export Data to Language: + + + + + + + + C++ / Root + + + + + Gnuplot + + + + + Python + + + + + Hermelin + + + + + + + + false + + + QTextEdit::NoWrap + + + true + + + false + + + + + + + + + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + listFiles + tabWidget + editPath + btnBrowse + comboX + comboY + editTitle + editSample + editUser + editContact + editKfix + editTimestamp + editA + editB + editC + editAlpha + editBeta + editGamma + editPlaneX0 + editPlaneX1 + editPlaneX2 + editPlaneY0 + editPlaneY1 + editPlaneY2 + tableProps + comboExport + textRoot + + + +
diff --git a/ui/settings.ui b/ui/settings.ui new file mode 100644 index 0000000..42f7e00 --- /dev/null +++ b/ui/settings.ui @@ -0,0 +1,701 @@ + + + SettingsDlg + + + + 0 + 0 + 451 + 407 + + + + Settings + + + true + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults + + + + + + + 0 + + + + General + + + + + + Reciprocal Space + + + + + + 1 + + + 10 + + + + + + + + 0 + 0 + + + + Max. Peak Order: + + + + + + + + 0 + 0 + + + + Structure Factor + + + 1 + + + + Show Structure Factor |F| + + + + + Show Intensity S=|F|² + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Number Precision + + + + + + 1 + + + 16 + + + 6 + + + + + + + + 0 + 0 + + + + General: + + + + + + + + 0 + 0 + + + + Graphical Views: + + + + + + + 1 + + + 16 + + + 4 + + + + + + + + + + Fonts + + + + + + + 0 + 0 + + + + General: + + + + + + + + 1 + 0 + + + + + + + true + + + + + + + + 0 + 0 + + + + Select Font... + + + + + + + + 0 + 0 + + + + 2D Views and Plots: + + + + + + + + 1 + 0 + + + + + + + true + + + + + + + + 0 + 0 + + + + Select Font... + + + + + + + + 0 + 0 + + + + 3D Views (if available): + + + + + + + + 1 + 0 + + + + + + + true + + + + + + + + 0 + 0 + + + + Select Font... + + + + + + + + + + Network + + + + + + + 0 + 0 + + + + Polling Interval (ms): + + + + + + + + 0 + 0 + + + + 100000 + + + 50 + + + 750 + + + + + + + + + + Dialogs + + + + + + Show Previews in Dialogs + + + true + + + + + + + Prefer Native Dialogs + + + + + + + + + + + Nicos Devices + + + + + + Sample + + + + + + Name: + + + + + + + + + + Lattice: + + + + + + + + + + + + + + Angles: + + + + + + + + + + + + + + Orient1: + + + + + + + + + + + + + + Orient2: + + + + + + + + + + + + + + Spacegroup: + + + + + + + + + + + + + + Theta: + + + + + + + + + + + + + + 2Theta: + + + + + + + + + + + + + + Psi0: + + + + + + + + + + + + + + Converts Nicos' left-handed coordinate system to Takin's right-handed one. + + + Flip Orientation Vector 2 + + + true + + + + + + + + + + Analyser + + + + + + Theta: + + + + + + + + + + + + + + 2Theta: + + + + + + + + + + + + + + d-Spacing: + + + + + + + + + + + + + + + + + Monochromator + + + + + + Theta: + + + + + + + + + + + + + + 2Theta: + + + + + + + + + + + + + + d-Spacing: + + + + + + + + + + + + + + + + + + + + + tabWidget + spinPrecGen + spinPrecGfx + checkNativeDlg + checkPreview + spinBragg + comboSFact + spinNetPoll + editGenFont + btnGenFont + editGfxFont + btnGfxFont + editGLFont + btnGLFont + editSampleName + editSampleLattice + editSampleAngles + editSampleOrient1 + editSampleOrient2 + editSampleSG + editSampleTheta + editSample2Theta + editSamplePsi0 + checkFlipOrient2 + editMonoTheta + editMono2Theta + editMonoD + editAnaTheta + editAna2Theta + editAnaD + buttonBox + + + + + buttonBox + accepted() + SettingsDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SettingsDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/sglist.ui b/ui/sglist.ui new file mode 100644 index 0000000..23e10ce --- /dev/null +++ b/ui/sglist.ui @@ -0,0 +1,328 @@ + + + SgListDlg + + + + 0 + 0 + 601 + 465 + + + + Space Group Types + + + true + + + + 4 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + Space Group Types + + + + 0 + + + 4 + + + + + true + + + + + + + Search Space Group Types + + + + + + + + + + 2 + 0 + + + + 0 + + + + Space Group Information + + + + 4 + + + + + Symmetry Operations: + + + + + + + true + + + + + + + Hermann-Mauguin Symbol: + + + + + + + true + + + + + + + Number: + + + + + + + true + + + + + + + l + + + l = + + + -99 + + + + + + + Show Transformation Matrices + + + + + + + Point / Laue Group: + + + + + + + true + + + + + + + Check Bragg Peak: + + + + + + + + 50 + false + false + true + + + + h + + + h = + + + -99 + + + + + + + k + + + k = + + + -99 + + + + + + + + Transformation + + + + 4 + + + + + + 0 + 0 + + + + x= + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + y= + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + z= + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + + + + + w= + + + 4 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + true + + + + + + + + + + + + tabWidget + listSGs + editFilter + tabWidget_2 + editNr + editHM + editLaue + spinH + spinK + spinL + checkMatrices + listSymOps + spinX + spinY + spinZ + spinW + listTrafo + + + + diff --git a/ui/spurions.ui b/ui/spurions.ui new file mode 100644 index 0000000..f9e299b --- /dev/null +++ b/ui/spurions.ui @@ -0,0 +1,352 @@ + + + SpurionDlg + + + + 0 + 0 + 434 + 521 + + + + Spurious Scattering + + + + + + General Settings + + + + + + false + + + E_i (meV): + + + + + + + false + + + 4 + + + 0.000000000000000 + + + 999.999900000000025 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Fixed E_i + + + true + + + + + + + Fixed E_f + + + + + + + Sync + + + true + + + true + + + + + + + + + + 1 + + + + Inelastic + + + + + + + 0 + 0 + + + + Settings + + + + + + Maximum Order: + + + + + + + 1 + + + 5 + + + + + + + λ Filter + + + true + + + + + + + + + + + + + + Bragg Tail + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Settings + + + + + + q Min (Å⁻¹): + + + + + + + + 1 + 0 + + + + 4 + + + -99.989999999999995 + + + 0.100000000000000 + + + + + + + q Max (Å⁻¹): + + + + + + + + 1 + 0 + + + + 4 + + + -99.989999999999995 + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + + + + + + + + + 1 + 0 + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + radioFixedEi + radioFixedEf + btnSync + spinE + tabWidget + checkFilter + spinOrder + textSpurions + spinMinQ + spinMaxQ + buttonBox + + + + + buttonBox + accepted() + SpurionDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SpurionDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + btnSync + toggled(bool) + spinE + setDisabled(bool) + + + 221 + 69 + + + 221 + 99 + + + + + btnSync + toggled(bool) + labelE + setDisabled(bool) + + + 221 + 69 + + + 85 + 99 + + + + +
diff --git a/ui/sqwparams.ui b/ui/sqwparams.ui new file mode 100644 index 0000000..b73030d --- /dev/null +++ b/ui/sqwparams.ui @@ -0,0 +1,98 @@ + + + SqwParamDlg + + + + 0 + 0 + 423 + 427 + + + + Parameters + + + true + + + + + + true + + + QAbstractItemView::SelectRows + + + true + + + false + + + + Variable + + + + + Type + + + + + Value + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SqwParamDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SqwParamDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/taz.ui b/ui/taz.ui new file mode 100644 index 0000000..cda2fe7 --- /dev/null +++ b/ui/taz.ui @@ -0,0 +1,981 @@ + + + TazDlg + + + + 0 + 0 + 870 + 633 + + + + Takin + + + + + + false + + + + + 6 + + + 4 + + + 6 + + + 2 + + + + + + 0 + 0 + + + + Qt::Vertical + + + + + 0 + 1 + + + + Qt::Horizontal + + + + + 0 + 0 + + + + true + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + + 0 + + + + + + 4 + 1 + + + + Instrument + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + Mono. d (Å): + + + + + + + + 0 + 0 + + + + Ana. d (Å): + + + + + + + + 0 + 0 + + + + Monochromator + + + + + + false + + + + + + + Sample + + + + + + true + + + + + + + + 0 + 0 + + + + Sc. Senses: + + + + + + + Analyser + + + + + + false + + + + + + + 3.355 + + + + + + + 3.355 + + + + + + + + + + + 4 + 1 + + + + Space Group + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + + <not set> + + + + + + + + + 0 + 0 + + + + Filter: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + System: + + + + + + + true + + + + + + + + + + + 3 + 0 + + + + Sample + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Powder + + + + + + + + 0 + 0 + + + + Atoms in Unit Cell + + + Atoms... + + + false + + + + + + + + + + + 6 + 1 + + + + 0 + + + + Real Lattice + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + β (°): + + + + + + + 90 + + + + + + + + 0 + 0 + + + + α (°): + + + + + + + 90 + + + + + + + 5 + + + + + + + 5 + + + + + + + 90 + + + + + + + + 0 + 0 + + + + a (Å): + + + + + + + + 0 + 0 + + + + c (Å): + + + + + + + 5 + + + + + + + + 0 + 0 + + + + γ (°): + + + + + + + + 0 + 0 + + + + b (Å): + + + + + + + + Recip. Lattice + + + + 4 + + + 2 + + + 4 + + + + + + 0 + 0 + + + + a (Å⁻¹): + + + + + + + + + + + 0 + 0 + + + + α (°): + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + b (Å⁻¹): + + + + + + + + + + + 0 + 0 + + + + β (°): + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + c (Å⁻¹): + + + + + + + + + + + 0 + 0 + + + + γ (°): + + + + + + + + 0 + 0 + + + + + + + + + + + + + 5 + 1 + + + + 1 + + + + Real Plane + + + + 4 + + + 2 + + + + + + 0 + 0 + + + + x: + + + + + + + 1 + + + + + + + 0 + + + + + + + 0 + + + + + + + + 0 + 0 + + + + y: + + + + + + + 0 + + + + + + + 1 + + + + + + + 0 + + + + + + + + 0 + 0 + + + + z: + + + + + + + 0 + + + true + + + + + + + 0 + + + true + + + + + + + 1 + + + true + + + + + + + + Recip. Plane + + + + 4 + + + 2 + + + + + 0 + + + + + + + + 0 + 0 + + + + y: + + + + + + + 0 + + + + + + + 1 + + + + + + + 0 + + + + + + + 0 + + + + + + + + 0 + 0 + + + + x: + + + + + + + 1 + + + + + + + + 0 + 0 + + + + z: + + + + + + + 0 + + + true + + + + + + + 0 + + + true + + + + + + + 1 + + + true + + + + + + + + + + + + + + + + groupSample + editA + editB + editC + editAlpha + editBeta + editGamma + editARecip + editBRecip + editCRecip + editAlphaRecip + editBetaRecip + editGammaRecip + editDescr + checkPowder + btnAtoms + comboSpaceGroups + editSpaceGroupsFilter + editCrystalSystem + groupScatteringPlane + editScatX0 + editScatX1 + editScatX2 + editScatY0 + editScatY1 + editScatY2 + editScatZ0 + editScatZ1 + editScatZ2 + editRealX0 + editRealX1 + editRealX2 + editRealY0 + editRealY1 + editRealY2 + editRealZ0 + editRealZ1 + editRealZ2 + checkSenseM + checkSenseS + checkSenseA + editMonoD + editAnaD + groupRecip + groupReal + + + + diff --git a/xmonteconvo b/xmonteconvo new file mode 120000 index 0000000..52de30a --- /dev/null +++ b/xmonteconvo @@ -0,0 +1 @@ +bin/xmonteconvo \ No newline at end of file