Сборка проекта при помощи cmake¶
Hello world¶
Создадим в рабочей директории два файла: main.cc и CMakeLists.txt (если вы находитесь в консоли, используйте команду touch main.cc CMakeLists.txt).
В файле main.cc напишем:
#include <iostream>
int main(int argc,char** argv)
{
std::cout<<"Hello world"<< std::endl;
return 0;
}
А в файле CMakeLists.txt:
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(pi-decay)
add_executable(pi-decay main.cc)
Разберем, что значат эти строки:
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)— устанавливает минимальную версию cmake используемую в проекте.project(pi-decay)— задает имя проекта, которое используется какcmake, так и внешними программами, например, IDE.add_executable(pi-decay main.cc— добавляет задание на создание исполняемого файл с именемpi-deacy, используя код из файлаmain.cc.
Теперь попробуем собрать проект, для этого мы создадим отдельную директорию в которой будет происходить сборка проекта, такую директорию обычно называют build. Никогда не собирайте проект прямо в той же директории где лежат файлы с кодом — запаритесь потом отделять зерна от плевел, создайте поддиректорию, её при необходимости будет легко удалить.
mkdir build && cd build
Затем запустите cmake в директории build, указав путь к директории с кодом.
cmake path/to/code
cmake сгенерирует файл Makefile, который будет использован программой make для сборки проекта. Выполните make в папке build
make
Готово, в директории должен появится файл pi-decay, который можно запустить:
./pi-decay
Установка GEANT4¶
TODO()
Подключение GEANT4 к нашему проекту¶
В первую очередь нужно активировать переменные окружения необходимые для работы GEANT4. Для этого нужно выполнить скрипт geant4.sh:
source path/to/geant4/instalation/geant4.sh
Для того чтобы не выполнять эту команду каждый раз, можно добавить её в файл ~/.bashrc. Тогда она будет автоматически выполнятся при каждом запуске терминала. Если вы хотите чтобы эти переменные окружения унаследовали графические приложения (например, ваша IDE), нужно или запускать их из консоли, или проводить настройку в соответствии с вашим графическим окружением.
Теперь добавим GEANT4 в наш проект, отредактировав файл CMakeLists.txt:
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(pi-decay)
option(WITH_GEANT4_UIVIS "Build example with Geant4 UI and Vis drivers" ON)
if(WITH_GEANT4_UIVIS)
find_package(Geant4 REQUIRED ui_all vis_all)
else()
find_package(Geant4 REQUIRED)
endif()
include(${Geant4_USE_FILE})
add_executable(pi-decay main.cc)
target_link_libraries(pi-decay ${Geant4_LIBRARIES})
Разберем внесенные модификации:
option(WITH_GEANT4_UIVIS "Build example with Geant4 UI and Vis drivers" ON— включает поддержку интерактивной и графической сессий.find_package(...)— автоматически ищет и подключает cmake-модули GEANT4 (не сами библиотеки!), что бы оно работало, должно быть выполнен скриптgeant4.sh.include(${Geant4_USE_FILE})— подключает заголовочные файлы GEANT4.target_link_libraries(pi-decay ${Geant4_LIBRARIES})— динамически присоединяет к нашему исполняемому файлу библиотеки GEANT4.
Для того что бы проверить что GEANT4 подключен правильно отредактируем наш файл main.cc:
#include "G4RunManager.hh"
int main(int argc, char** argv)
{
G4RunManager* runManager = new G4RunManager;
delete runManager;
}
Пересоберите проект и запустите исполняемый файл, что бы убедится что вы все сделали правильно.
Подключаем дополнительные файлы и создаем заготовку для моделирования¶
Пока мы создали проект состоящий только из одного файла с кодом, однако в реальности код проект распределяется по нескольким файлам, которые отвечают за какую отдельную часть проекта. Например, для того чтобы начать симуляцию в GEANT4 пользователь обязан самостоятельно описать геометрию своего эксперимента, задать генератор первичных событий и выбрать используемую физику. Давайте создадим заготовку содержащие отдельные файлы для геометрии и генератора первичных частиц и подключим их к нашему проекту.
Для начала создадим две директории: include в которой мы будем размещать заголовочные файлы и src в которой мы будем размешать файлы с реализацией.
В директорию include мы поместим файлы DetectorConstruction.hh и PrimaryGeneratorAction.hh со следующим содержанием (его суть мы разберем в следующих главах).
DetectorConstruction.hh:
#ifndef PI_DECAY_DETECTORCONSTRUCTION_HH
#define PI_DECAY_DETECTORCONSTRUCTION_HH
#include <G4VUserDetectorConstruction.hh>
class DetectorConstruction : public G4VUserDetectorConstruction{
public:
G4VPhysicalVolume *Construct() override;
};
#endif //PI_DECAY_DETECTORCONSTRUCTION_HH
PrimaryGeneratorAction.hh:
#ifndef PI_DECAY_PRIMARYGENERATORACTION_HH
#define PI_DECAY_PRIMARYGENERATORACTION_HH
#include <G4VUserPrimaryGeneratorAction.hh>
#include <G4ParticleGun.hh>
class PrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction{
public:
PrimaryGeneratorAction();
void GeneratePrimaries(G4Event *anEvent) override;
private:
G4GeneralParticleSource *particleSource;
};
#endif //PI_DECAY_PRIMARYGENERATORACTION_HH
А в директории src поместим файлы DetectorConstruction.cc и PrimaryGeneratorAction.cc:
DetectorConstruction.cc:
#include <G4NistManager.hh>
#include <G4Box.hh>
#include <G4PVPlacement.hh>
#include "G4LogicalVolume.hh"
#include "DetectorConstruction.hh"
#include "G4SystemOfUnits.hh"
G4VPhysicalVolume *DetectorConstruction::Construct() {
// Get nist material manager
auto nist = G4NistManager::Instance();
// Option to switch on/off checking of volumes overlaps
G4bool checkOverlaps = true;
//
// World
//
G4double world_sizeXY = 20*meter;
G4double world_sizeZ = 30*meter;
G4Material* world_mat = nist->FindOrBuildMaterial("G4_AIR");
G4Box* solidWorld =
new G4Box("World", //its name
0.5*world_sizeXY, 0.5*world_sizeXY, 0.5*world_sizeZ); //its size
G4LogicalVolume* logicWorld =
new G4LogicalVolume(solidWorld, //its solid
world_mat, //its material
"World"); //its name
G4VPhysicalVolume* physWorld =
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at (0,0,0)
logicWorld, //its logical volume
"World", //its name
0, //its mother volume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
return physWorld;
}
PrimaryGeneratorAction.cc:
#include "PrimaryGeneratorAction.hh"
void PrimaryGeneratorAction::GeneratePrimaries(G4Event *anEvent) {
particleSource->GeneratePrimaryVertex(anEvent);
}
PrimaryGeneratorAction::PrimaryGeneratorAction()
: G4VUserPrimaryGeneratorAction(){
particleSource = new G4GeneralParticleSource();
}
Отредактируем файл main.cc, чтобы использовать эти новые файлы:
#include <DetectorConstruction.hh>
#include <PrimaryGeneratorAction.hh>
#include <QGSP_BERT.hh>
#include <G4VisManager.hh>
#include <G4VisExecutive.hh>
#include <G4UIExecutive.hh>
#include <G4UImanager.hh>
#include "G4RunManager.hh"
int main(int argc, char **argv) {
G4UIExecutive *ui = nullptr;
if (argc == 1) {
ui = new G4UIExecutive(argc, argv);
}
G4RunManager *runManager = new G4RunManager;
runManager->SetUserInitialization(new DetectorConstruction());
runManager->SetUserInitialization(new QGSP_BERT);
runManager->SetUserAction(new PrimaryGeneratorAction());
runManager->Initialize();
G4VisManager *visManager = new G4VisExecutive;
visManager->Initialize();
// Get the pointer to the User Interface manager
G4UImanager *UImanager = G4UImanager::GetUIpointer();
// Process macro or start UI session
//
if (!ui) {
// batch mode
G4String command = "/control/execute ";
G4String fileName = argv[1];
UImanager->ApplyCommand(command + fileName);
} else {
// interactive mode
UImanager->ApplyCommand("/control/execute init_vis.mac");
ui->SessionStart();
delete ui;
}
delete visManager;
delete runManager;
}
Теперь давайте подключим эти файлы к нашему проекту, добавив эти строчки в файл CMakeLists.txt:
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cc)
Давайте разберем что они делают:
include_directories(${PROJECT_SOURCE_DIR}/include)— подключает заголовочные файлы из указанной директории,${PROJECT_SOURCE_DIR}это перменная указывающая путь к корневой директории проекта.file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cc)— создает переменнуюsources, которая содержит список файлов соответвующих заданной маске${PROJECT_SOURCE_DIR}/src/*.cc.
Теперь изменим команду add_executable(pi-decay main.cc на
add_executable(pi-decay main.cc ${sources}), для того чтобы добавить файлы из списка sources как нашему исполняемому файлу. Скомпиируйте проект, что бы убедится что вы правильно все подключили.