Wednesday, April 8, 2015

Занятие 3. Задание физических процессов в Geant4.

На мой взгляд, это самое сложное, с чем может столкнуться пользователь при моделировании своего эксперимента. Тем не менее, я постараюсь изложить данный этап моделирования как можно более понятно и по возможности подробно. Повторюсь, что если у читателя возникнут вопросы, я всегда готова ответить на них в комментариях.

Как и в предыдущем посте про физические модели, сегодня мы будем говорить о физике применительно к адронной терапии. Примерный набор физических процессов,  которые используются в этой области физики можно посмотреть в примере "hadrontherapy" в директории "/examples/advanced/hadrontherapy" внутри дистрибутива Geant4 10.01 (файл HadrontherapyPhysicsList.сс). Или в нашем примере - там, по сути, используется та же физика.

Теперь поговорим подробно о способах, которыми эта физика задается. Всю систему моделирования физики внутри Geant4 можно разделить на три принципиальных элемента:
  1. Физическая модель - генерирует конечное состояние частицы после взаимодействия и обновляет параметры моделируемой частицы.
  2. Физический процесс - содержит необходимые таблицы поперечных сечений и используемые физические модели.
  3. Список физических процессов (Physics List) - как понятно из названия, элемент, который содержит в себе набор физических процессов для каждой частицы.
При написании программы пользователь обязательно должен создать свой набор физических процессов в своем классе, который должен быть унаследован от G4VUserPhysicsList. После чего указатель на него он передает в G4RunManager. Вот как это должно выглядеть в коде в функции main:
G4VUserPhysicsList* physicsList = new PolyethylenePhysicsList;
runManager->SetUserInitialization(physicsList);
Но есть несколько серьезных упрощений. Во первых, Geant4 предоставляет уже готовые наборы физики (Reference Physics List), предназначенные для различных областей. Например нам более менее подходит QGSP_BERT, ориентированный на эксперименты с адронами. Какие модели туда входят и, вообще какие готовые наборы физики нам подходят вы сможете понять отсюда. Обратите внимание на раздел "Medical and industrial neutron applications" и "Low energy dosimetric applications". Вообще нам подходят разделы с ключевыми словами hadron и low energy.
Такие готовые наборы физики подключаются очень просто. Вот так:
runManager->SetUserInitialization(new QGSP_BIC);
Только не забудьте сделать include заголовка класса, в данном случае QGSP_BIC.hh.

Второй по убыванию сложности метод задания физики - это наследование класса G4VModularPhysicslist, который, в свою очередь является наследником класса G4VUserPhysicsList. У нас получается две ступени наследования!
В функции main это будет выглядеть так:
  G4VModularPhysicsList* physicsList = new PolyethylenePhysicsList;
Класс G4VModularPhysicsList создан для того, чтобы мы могли построить физику из набора блоков, о которых мы говорили, когда обсуждали физику в предыдущем посте: G4EmStandardPhysics, G4EmExtraPhysic и так далее. Если помните, то мы выяснили, что каждый из этих классов отвечает за свою область физики. Более того, каждый из этих классов является наследником одного и того же материнского класса G4VPhysicsConstructor. Этот класс содержит две важные функции, которые должен определить по своему каждый класс, который его наследует: ConstructParticle() и ConstructProcess(). Это означает, что обе эти функции по-своему определены в G4EmStandardPhysics и во всех других таких классах. В первой функции создаются все частицы, участвующие в этом разделе физики (в том числе теоретически возможные вторичные), во второй функции к каждой такой созданной частице подсоединяются соответствующие ей физические процессы. Пожалуйста, запомните это и не спутайте дальше с точно так же называющимися функциями в классе G4VUserPhysicsList! О которых мы еще поговорим.

Итак, что у нас есть: класс G4VModularPhysicsList и набор дочерних классов от G4VPhysicsConstructor. Для использования их в нашем G4VModularPhysicsList, в классе G4VModularPhysicsList есть специальная функция RegisterPhysics, в которую как аргумент передается указатель на объект нужного нам класса, наследующего G4VPhysicsConstructor. Взгляните в пост от занятия 2 и 3/4. Там как раз показан список из таких функций RegisterPhysics(). (Обратите внимание, что этот список должен содержаться в конструкторе нашего класса - наследника G4VModularPhysicsList.) Внутри функции RegisterPhysics() переданный в нее класс физики добавляется в массив и хранится там. Что же происходит дальше? Когда мы запускаем расчет, G4RunManager обращается к нашему дочернему классу G4VModularPhysicsList и вызывает в нем две функции по очереди ConstructParticle() и ConstructPhysics(), которые (по доброте душевной разработчиков) называются точно так же, как и функции класса G4VPhysicsConstructor. В чем отличие? В том что эти две функции, пустые, с точно такими же названиями содержатся в классе G4VUserPhysicsList. Когда класс G4VModularPhysicsList наследует класс G4VUserPhysicsList, эти функции с точно такими же названиями переходят в G4VModularPhysicsList. Но здесь они уже не пусты! Класс G4VModularPhysicsList их определяет. В своей функции ConstructParticle() он обращается к массиву физических классов - наследников G4PhysicsConstructor и вызывает у каждого по очереди его собственную функцию ConstructParticle(). То же самое происходит и в функции ConstructPhysics() класса G4VModularPhysicsList - в ней идет обращение к тому же массиву, и на каждый класс, содержащийся там, вызывается его функция ConstructPhysics().

Теперь займемся классом G4VUserPhysicsList и самым сложным способом задания физики. Он сложен потому, что тут мы не используем модули, ту мы вручную будем создавать каждую частицу и к ней присоединять все нужные физические процессы. Вообще, мы можем пойти еще дальше, и к каждому процессу вручную подсоединить нужные физические модели. Особенно это касается адронной физики, где моделей, описывающей ядерные взаимодействия великое множество для каждого диапазона энергий.
Как я уже говорила, в классе G4VUserPhysicsList есть две пустые функции ConstructProcess() и ConstructParticle(), которые нам обязательно надо задать. В предыдущем случае за нас это делал G4VModularPhysicsList, но теперь мы сыграем в Чака Норриса и сделаем все сами.
Сначала один не очень очевидный факт. Задавать упомянутые функции мы будем точно так же, как они задаются в классах типа G4EmStandardPhysics (помните, что у их материнского класса точно такие же по названию функции?) с той лишь разницей, что теперь мы создаем все возможные в нашем эксперименте частицы и подключать к ним все возможные для них физические процессы.
Давайте заглянем в файл-исходник класса G4EmStandardPhysics вот здесь и посмотрим как это делается. С функцией ConstructParticle() все довольно просто. Создаются классы - синглетоны для каждого типа частицы, описывающие ее свойства. Во всей программе возможен только один объект каждого такого класса.
Что же происходит в функции ConstructProcess()? Обратите внимание на следующий кусок кода:

theParticleIterator->reset();
while( (*theParticleIterator)() ){
     G4ParticleDefinition* particle = theParticleIterator->value();
     G4String particleName = particle->GetParticleName();
     if(verbose > 1)
       G4cout << "### " << GetPhysicsName() << " instantiates for " 
              << particleName << G4endl;
 
     if (particleName == "gamma") {
       ph->RegisterProcess(new G4PhotoElectricEffect(), particle);
       ph->RegisterProcess(new G4ComptonScattering(), particle);
       ph->RegisterProcess(new G4GammaConversion(), particle);...
Здесь происходит следующее. Используется объект theParticleInterator, который является static и доступен из любой области программы. Он пробегает по всем инициализированным нами частицам и по очереди возвращает указатель на каждую из них. Это значит, что цикл while выполняется, пока мы не переберем все частицы.

Следующей строчкой после инициализации цикла мы получаем указатель на частицу - particle и в зависимости от того как она называется (функция GetParticleName()), мы подключаем к ней процессы, относящиеся к данному типу частицы. Делаем это мы с помощью множественных if циклов. Обратите внимание сколько их много. Первый из них, для гамма кванта, показан здесь.

Для того, чтобы понять, что происходит в цикле if также потребуются некоторые усилия. Обратите внимание на функцию RegisterProcess! Здесь мы имеем дело с классом G4PhysicsListHelper, а именно его объектом ph. Рядом с ним не стоит название класса, потому что в начале функции ConstructProcess, в которой мы сейчас находимся, указатель на него уже получен (найдите это место). Обратите внимание, что класс G4PhysicsHelper static.

Этот класс существует исключительно для того, чтобы облегчить процесс поключения процессов к частице. Внутри функции RegisterProcess он имеет дело с классом G4ProcessManager самой частицы. Он проверяет какие процессы уже к ней поключены, и поключает новый процесс, ставя ему в соответствие очередь, в которую он вызывается.

Эта очередь - нетривиальная вещь, так как она продиктована физикой процесса. Есть три главных этапа вызова процессов во время одного шага частицы - AlongStepDoIt, PostStepDoIt, AtRestDoIt.  В зависимости от такого какой процесс - непрерывный или дискретный - он добавляется в список к одному (иногда к нескольким) из этих этапов. Например, поглощение частицы в конце трека - это чистый AtRestDoIt процесс, а неупругое столкновение протона с ядром с рождением вторичных частиц - PostStepDoIt процесс. Внутри каждой этой группы есть свой список последовательности вызова процессов.  Все это можно подклучать вручную, но тогда нам не надо использовать G4PhysiсsListHelper, а получать от каждой частицы ее G4ProcessManager. Если вам интересно как это делается и как правильно выстраивать процессы в очередь - об этом написана целая глава в User's Guide for Application Developers  для Geant4 (она доступна в pdf бесплатно здесь). Страница 177, раздел 5.2.

Вернемся к нашему if циклу.  Внутри него мы поключаем к каждому типу частицы процессы ей соответствующие с помощью функции RegisterProcess, в которую в качестве аргументов передаются указатели на частицу и на процесс для нее.

But we need to go even deeper. Каждый процесс имеет внутри себя модель или набор моделей, которые, собственно, всю работу и выполняют. Несколько моделей бывает нужно, если каждая из них работает, например, для своего диапазона энергии. Или если одна модель теоретическая, другая использует экспериментальные таблицы сечений.

Помните, на лекции я не смогла ответить на вопрос чем функция электромагнитного процесса SetEmModel отличасется от AddEmModel? После прочтения километра кода отвечаю. Если вы хотите использовать одну модель, то поключайте ее через функцию SetEmModel обязательно с номером 1 как второй аргумент функции! Если будет 0 или 2 или больше, программа эту модель проигнорирует! AddEmModel используйте если вам надо подключить несколько моделей. Причем цифра второго аргумента должна соответствовать узости специализации каждой модели. Например, если у вас есть две модели, одна из которых для низких энергий, а вторая для широкого диапазона - то модель низких энергий должна идти под цифрой 2, а общая модель под цифрой 1. И не используйте нулей, код программы игнорирует модели под нулевым номером. Странно, согласна.

В завершение я хочу упомянуть, что у электромагнитных процессов есть механизмы ограничения шага частицы, которые повышают точность моделирования. Они предусмотрены и для торможения частицы, и для многократного рассеяния, и общие. Вообще, физику можно использовать и без настройки этих параметров, так как они разумно выставлены по умолчанию. Однако, в специфических экспериментах это может понадобится. По поводу этих алгоритмов я напишу отдельный пост, но, к сожалению, на английском языке. Дело в том, что это может быть интересно иностранному сообществу пользователей тоже.

Wednesday, April 1, 2015

Занятие 2 и 3/4. Behind the scenes: Обзор физических моделей для протонов, содержащихся в Geant4

Сегодня я хочу изложить подготовительную информацию для нашего следующего, третьего занятия. На третьем занятии мы будем говорить о том, как задавать набор физических процессов и соответствующих моделей в Geant4. Сегодня же я хочу отвлечься от кодинга и немного обсудить физику, заложенную в эти модели, а так же логику их использования при описании эксперимента.
Сначала загляните в файл PolyethylenePhysicsList.cc и обратите внимание на эти строки:
RegisterPhysics(new G4EmStandardPhysics_option3);
RegisterPhysics(new G4HadronPhysicsINCLXX);
RegisterPhysics(new G4EmExtraPhysics);
RegisterPhysics(new G4HadronElasticPhysics);
RegisterPhysics(new G4StoppingPhysics);
RegisterPhysics(new G4IonBinaryCascadePhysics);
RegisterPhysics(new G4NeutronTrackingCut);
//    RegisterPhysics(new G4DecayPhysics);
//    RegisterPhysics(new G4RadioactiveDecayPhysics);
Вы видите, что все применяемые физические модели разбиты на крупные разделы. Среди них есть основные:
  • Электромагнитная физика (G4EmStandardPhysics_option3). Она включает в себя основные электромагнитные процессы для протонов: многократное рассеяние на электронных оболочках атомов и ионизационное торможение в веществе. Кроме того, в этот раздел входят все процессы и для других частиц, которые могут родиться в эксперименте как вторичные. Например, процессы для фотонов включают в себя: образование пар (здесь оно немного непривычно для меня называется G4GammaConversion), эффект Комптона, Релеевское рассеяние, фотоэлектрический эффект. И так далее. Каждому типу частицы в этом разделе ставятся в соответствие основные электромагнитные процессы ей соответствующие. Как это все подключается мы обсудим на следующем, третьем, занятии, посвященном программированию.
  • Упругое рассеяние адронов (G4HadronElasticPhysics). В этом разделе описывается процесс упругого рассеяния адронов на ядрах вещества, а не на электронных оболочках.
  • Неупругое рассеяние адронов (G4HadronPhysicsINCLXX). В этом разделе описывается процесс неупругого рассеяния адронов на ядрах вещества.
Оставшиеся разделы в списке не настолько важны для нас, но, тем не менее, рассмотрим и их:
  • Дополнительная электромагнитная физика (G4EmExtraPhysics). В нее входит три подраздела:
  1. Синхротронное излучение (G4SynchrotronRadiation). Электромагнитное излучение, испускаемое ультрарелятивистской заряженной частицей, ускоряемой радиально (av). По названию понятно, что такое излучение было впервые обнаружено в ускорителе сихротроне. В нашем случае сихротронное излучение возможно, если быстрые электроны будут двигаться через магнитное поле (мы пробовали его включать на прошлом занятии). Для более тяжелых частиц синхротронное излучение в нашем эксперименте невозможно, так как они не достигают релятивистских энергий (напомню, что энергия протонов в пучке в нашем эксперименте - 160 МэВ).
  2. Фотоядерный эффект (G4PhotoNuclearProcess) или поглощение гамма-кванта ядром. При этом ядро получает избыток энергии без изменения своего нуклонного состава. Если переданная ядру энергия превосходит энергию связи нуклона в ядре, то распад образовавшегося составного ядра происходит чаще всего с испусканием нуклонов, в основном нейтронов.
  3. Взаимодействие мюона с ядром (G4MuonNuclearProcess) путем обмена виртуальным фотоном.
  • Ядерный захват остановившихся отрицательно заряженных частиц (G4StoppingPhysics). Применим для остановившихся  анти-протона, μ-, K-, Σ-, Ξ-, Ω- , анти - Σ+.
  • Ядерные рекакции распространенных ионов с ядром (G4IonBinaryCascadePhysics). Моделируется с помощью бинарного внутриядерного каскада. Ионы могут возникать как продукты неупругих взаимодействий протонов с ядрами вещества.
  • Ограничитель на моделирование трека нейтронов (G4NeutronTrackingCut).  Так как нейтрон - нейтральная частица, он не взаимодействует с электронными оболочками атомов. Замедление нейтронов происходит при упругих столкновениях с ядрами. Если до столкновения ядро покоилось, то после столкновения оно приходит в движение, получая от нейтрона некоторую энергию, вследствие чего нейтрон замедляется. Однако это замедление нейтронов не может привести к их полной остановке из-за теплового движения ядер. В итоге, необходим ограничитель на трекинг нейтронов по времени или по энергии нейтрона.
Также можно подключить оставшиеся два раздела физики связанные с распадом нестабильных частиц (G4DecayPhysics) и радиактивным распадом ядер (G4RadioactiveDecayPhysics). Однако, эти процессы вносят чрезвычайно малый вклад в результат нашего эксперимента и их можно не учитывать.

Вернемся к основным процессам взаимодействия протонов с веществом и рассмотрим их более подробно.
  • G4EmStandardPhysics_option3
При подключении раздела электромагнитной физики, протонам (и антипротонам) приписываются набор определенных физических процессов взаимодействия. Каждый такой физический процесс содержит в себе модель, которая описывает данное взаимодействие. Важно, что один и тот же физический процесс могут описывать разные модели, и эти модели взаимозаменяемы. То есть мы можем поменять модель в этом процессе или подключить несколько моделей, определив для каждой диапазон энергий частиц, в котором она применима.

Итак, обсудим процессы, которые у нас используются в электромагнитной физике:

Упругое рассеяние протонов на электронных оболочках атомов.  Как раз в этом месте есть небольшая сложность. Для этого взаимодействия предусмотрена два варианта процесса, а не модели. Дело в том, что Geant4 позволяет описывать это взаимодействие двумя разными способами.

Первый - это детализированное описание рассеяния в отдельности. Такой процесс так и называется G4CoulombScattering. К нему подключается модель G4eCoulombScatteringModel. В этом процессе, каждое упругое рассеяние моделируется отдельно. Преимущество этого процесса в том, что он использует таблицы сечений взаимодействия, полученные теоретически, в отличие от второго варианта, процесса многократного рассеяния. Недостатком является то, что из-за того что моделируется каждое взаимодействие, количество шагов (G4Step) частицы сильно возрастает по сравнению с многократным рассеянием. Следовательно, возрастает и время расчета, в сотни, тысячи раз. Такой процесс имеет смысл подключать только если мы имеем дело со средой низкой плотности, например, воздухом. Физическая модель G4hCoulombScatteringModel основана на теории рассеяния Вентзеля (Wentzel). Подробное описание теории можно посмотреть в Geant4 Physics Reference Manual стр. 67.

Второй способ описания - многократное рассеяние, процесс G4hMultipleScattering (напомню, что буква h в названиях процессов, означает что они применимы к адронам). К нему могут быть подключены две модели, каждую из которых мы рассмотрим отдельно:
  1. G4UrbanMscModel - модель Урбана (Urban), которая применима для всех типов частиц. Модель Урбана использует специально подобранные функции углового и пространственного распределения после рассеяния, которые имеют те же моменты случайной величины, что и те, которые выдает теория Льюиса (Lewis). Проще говоря, теория Урбана делает попытку упрощенного описания теории Льюиса, которая основана на строгом решении уравнения диффузии. Подробно теорию Льиса можно изучить в его статье здесь.
  2. G4WentzelVIModel - модель, относящаяся в смешанным алгоритмам. Такой алгоритм моделирует лобовые столкновения по отдельности используя модель однократного кулоновского рассеяния. Мягкие же столкновения с отклонением на небольшие углы, меньшие (по умолчанию, параметр можно менять) 0,2 рад, моделируются с помощью модели Wentzel-VI (как следует из названия).
Ионизационные потери протонов при прохождении через вещество. Потери энергии при прохождении через вещество протонов обусловлены прежде всего взаимодействием с электронными оболочками атомов, ионизацией и возбуждением их. Моделирование ионизационных потерь частицы делится на две фазы: дискретное моделирование каждого взаимодействия с рождением вторичных частиц и непрерывные потери энергии ниже задаваемого порога энергии частицы. Из имеющихся моделей в Geant4 для этого процесса нам подходит G4BetheBlochModel, название которой говорит само за себя.

  • G4HadronElasticPhysics 
Этот раздел физики моделирует упругое столкновение протонов с ядрами вещества. Внутри него содержится нужная и единственная мадель для протонов по умолчанию G4ChipsElasticModel. Она моделирует упрогое рассеяние адронов на ядре, используя таблицы сечений и модель взаимодействия Chiral Invariant Phase Space (ChIPS). Подробнее о ней можно почитать в Geant4 Physics Reference Manual на странице 431. Вообще CHIPS моделирует фрагментацию адронных систем на адроны, кластеризацию нуклонов в ядре и механизмы взаимодействия адронов и фотонов с ядерной материей (как частный случай - упругое рассеяние). 
  • G4HadronPhysicsQGSP_BIC ( и другие варианты: G4HadronPhysicsFTFP_BERT G4HadronPhysicsFTF_BIC и остальные классы, содержащие в названии BIC и BERT) или G4HadronPhysicsINCLXX
Раздел физики, отвечающий за моделирование неупругого взаимодействия адронов в ядрами. В нем существует несколько моделей и комбинаций моделей, однако, их замена не должна сильно влиять на результат эксперимента, так как неупругое столкновение протона с ядром - довольно редкое взаимодействие.

Прежде всего, первая часть аббревиатур QGS, FTF - обозначают то, что в соответствующих разделах физики используются модели Quark Gluon String и Fritiof, которые применимы только при энергиях протонов больше и значительно больше 1 ГэВ. Это не наш случай, поэтому формально эти модели в нашем эксперименте не будут вызываться вообще, поэтому первый кусок оббревиатуры не для нас, а для собратьев космофизиков.

Вторая часть аббревиатуры важнее. BIC - это Binary Cascade Model. В ней моделируется внутриядерный "путь" налетевшего протона и вторичных частиц такого неупругого взаимодействия. В каждый момент времени происходит взаимодействие налетевшего протона и только одного нуклона ядра, последовательно. Отсюда взялось название - бинарный каскад. Такой каскад останавливается как только энергия вторичных частиц становится ниже пороговой (она является нижней энергетической границей модели), которая составляет около сотни МэВ и может быть изменена. Дальше в игру вступают так называемая precompound model - модель, которая позволяет плавно перейти от кинетической стадии реакции к стадии равновесного ядра.

BERT - второй вариант окончания аббревиатуры - Bertini Cascade Model.  В ней ядро моделируется как слоистая концентрическая структура, каждый слой которой имеет постоянную плотность - имитация изменяющейся ядерной плотности. Каскад начинается, когда налетающая частица сталкивается с ядром и рождает вторичные частицы (при этом, заметьте, вторичнае частицы на этот момент являются кластерами нуклонов внутри ядра). Вторичные частицы в свою очередь могут взаимодействовать с другими нуклонами или отдать свою энергию ядру и быть поглощенными. Наступает фаза возбужденного ядра (описывается экситонной моделью), которое проходит стадию релаксации и испускает энергию в виде вторичных частиц. Эту фазу как раз и описывают G4PreCompoundModel и G4CascadeDeexcitation - две модели на выбор, которые используются внутри Bertini Cascade для моделирования переходя ядра в равновесное состояние. В Bertini Cascade по умолчанию стоит вторая, в Binary Cascade жестко поставлена первая. Это связано с особенностями описания модели. 
Кстати, подробнее о внутриядеоном каскаде и экситонной модели можно почитать здесь.

Monday, March 9, 2015

Занятие 2. Базовое описание материалов, геометрии и однородных полей в Geant4

Внимание! Данная статья подразумевает знание следующих понятий из C++:

  1. Класс. Члены класса. Public, private члены класса.
  2. Конструктор и деструктор класса.
  3. Наследование класса и переопределение в дочернем функций материнского класса.
  4. Объявление функций. Аргументы функций и значения, возвращаемые функциями.
  5. Файл заголовка (header file) и файл с кодом (source file). Директивы  #include, #ifdef, #ifndef, #else, #endif.
  6. Создание (инициализация) объекта определенного класса. Ключевое слово new и delete. Указатель на объект.
  7. Ключевое слово static.

На примере Example1, который моделирует реальный физический эксперимент, мы изучим как задается геометрия в Geant4. Эксперимент схематично нарисован ниже.

Начнем с того, что изучим файл, содержащий функцию main, который называется Polyethylene.cc. В Geant4 подразумевается определенная структура программы, в которой происходит инициализация объектов в определенной последовательности. Если мы забежим вперед и, скажем, запустим расчет до того, как мы создали геометрию то, само собой, программа вылетит с ошибкой. Если говорить точнее, она даже не соберется.

В начале файла содержится большое количество необходимых инклюдов классов, которые нам будут нужны в дальнейшем. Пока стоит обратить внимание на следующий кусок:
#ifdef G4MULTITHREADED
#include "G4MTRunManager.hh"
#else
#include "G4RunManager.hh"
#endif
И ниже:
#ifdef G4MULTITHREADED
    G4MTRunManager* runManager = new G4MTRunManager;
    runManager->SetNumberOfThreads(1);
#else
    G4RunManager* runManager = new G4RunManager;
#endif
В первом куске содержится директива препроцессору, сообщающая о том, что если мы включили параметр G4MULTITHREADED на стадии cmake, то будет включен заголовок G4MTRunManager.hh (многопоточная версия класса G4RunManager), в другом случае будет включен G4RunManager. G4RunManager - самый главный класс в Geant4, который управляет всем: инициализацией геометрии, подключением физики, продвижением частицы через геометрию и т.д. Его функция Initialize() вызывается в main последней, уже после того как все условия эксперимента заданы.
Во втором куске инициализируется класс G4RunManager или, в многопоточной версии, класс G4MTRunManager с последующим заданием количества потоков.

Теперь мы дошли до этапа инициализации класса, содержащего геометрию.
    PolyethyleneDetectorConstruction* massWorld = new PolyethyleneDetectorConstruction;
    massWorld->RegisterParallelWorld(new PolyethyleneParallelWorld("PolyethyleneParallelWorld"));
    runManager->SetUserInitialization(massWorld);
В первой строчке объект класса с геометрией, собственно, инициализируется. Вторую строчку мы пока пропускаем - это предмет отдельного занятия. В третьей строчке указатель на объект класса с геометрией передается в G4RunManager. Теперь он знает все о нашей геометрии.
Теперь поговорим о том, что же это за класс PolyethyleneDetectorConstruction. Вы, наверно, обратили внимание, что его название явно связано с названием эксперимента. Это не случайно. Класс геометрии - это класс, который мы обязательно должны написать сами, наследуя класс G4VUserDetectorConstruction, содержащий пустую функцию Construct().
Давайте убедимся в этом сами. Наводим курсор на подсвеченное название класса PolyethyleneDetectorConstruction и нажимаем F2. Мы видим файл заголовка этого класса и вот такую строчку:
class PolyethyleneDetectorConstruction : public G4VUserDetectorConstruction
Эта конструкция и означает, что мы унаследовали класс G4VUserDetectorConstruction. Теперь если мы проведем ту же операцию с названием класса G4VUserDetectorConstruction, то окажемся в его файле заголовка и увидим такую строчку:
virtual G4VPhysicalVolume* Construct() = 0;
Она означает, что материнский класс G4VUserDetectorConstruction содержит пустую функцию Construct(), "= 0" всегда говорит о том, что функцию надо определить в дочернем классе обязательно.

Настало время задать материалы, которые вместе с геометрией описываются в функции Construct() нашего класса PolyethyleneDetectorConstruction. Для того, чтобы выделить подзадачу задания материалов отдельно (что является хорошим стилем в объектно ориентированном программировании) я создала свою собственную фунцию InitializeMaterials() в нашем классе в разделе private (так как никакому другому классу, кроме конкретно этого, эта функция не понадобится). Проверьте это сами. Обратите внимание, что функция ничего не возвращает, void.

Поговорим о том, как задаются материалы в Geant4. Теоретически, можно создать любые элементы, изотопы и материалы самим, вручную. Но обычно это не нужно, так как Geant4 содержит большую базу данных элементов и материалов. Класс, который обращается к этой базе данных (которая называется NIST) и передает указатели на нужные нам элементы и материалы называется G4NistManager. Это класс static и singleton, что означает что он доступен отовсюду из нашей программы и может быть инициализирован только один раз. Что означает, что может быть только один объект этого класса в нашей программе, и понятно почему - материал не может быть определен в двух разных местах, неоднозначно.
Итак, если класс G4NistManager static, то это означает, что мы можем прямо сейчас, находясь в функции InitializeMaterials() получить на него указатель. Смотрим в код файла PolyethyleneDetectorConstruction.cc (Напоминаю, что список всех файлов, относящихся к нашей программе, содержится слева в окне QtCreator).
void PolyethyleneDetectorConstruction::InitializeMaterials()
{
    G4NistManager* nistManager = G4NistManager::Instance();
Всегда, когда мы будем иметь дело со static файлом, мы будем получать на него указатель такоей же конструкцией через Instance() вместо new. new создает новый объект класса, а, повторюсь, объект этого класса должен быть только один. Теперь посомотрим на следующие строчки.
G4Element* H = nistManager->FindOrBuildElement(1);
Здесь мы получаем от G4NistManager указатель на необходимый элемент (в данном случае водород) путем вызова его функции FindOrBuildElement, которая принимает как аргумент номер элемента. Дальше идут точно такие же строчки, которые возвращают нам указатели на другие элементы, которые понадобятся нам при создании материалов. Обратите внимание, что мы не создаем элементы - мы всего лишь получаем на них указатели. Сами элементы уже созданы внутри G4NistManager, второй раз создавать их не имеет смысла.
После того, как мы получили указатели на все необходимые нам элементы, мы можем начать конструировать материалы. Опять обращу внимание, если мы используем материал из базы данных, то нам не надо его создавать через new, в противном случае мы будем использовать new.
Итак, первый пример получения указателя на материал из базы данных полностью аналогичен получению указателя на элемент из базы данных:
G4Material* Air = nistManager->FindOrBuildMaterial("G4_AIR");
Дальше я добавляю его в список материалов, который является private членом нашего класса PolyethyleneDetectorConstruction для того, чтобы мы могли воспользоваться этими материалами из другой функции нашего класса, а именно, из функции Construct(). Посмотрим еще ниже по коду и увидим такой кусок:
    G4Material* Brass = new G4Material("Brass", 8.50*g/cm3, 4);
    Brass->AddElement(Zn, 0.354);
    Brass->AddElement(Cu, 0.6175);
    Brass->AddElement(Pb, 0.025);
    Brass->AddElement(Fe, 0.0035);
    MaterialMap["Brass"] = Brass;
Здесь мы создаем материал латунь своими руками. Сделать так мне пришлось, потому что мне нужен был определенный сплав с определенной массовой долей каждого элемента и плотностью. Первой строчкой мы создаем новый объект класса G4Material через new. Перейдите по F2 в файл заголовка этого класса и просмотрите его функции в разделе public. Повторюсь, что к функциям из раздела private мы не имеем доступа извне. Можно увидеть что функция AddElement, которую мы вызываем впоследствии, принимает как аргумент указатель на элемент и его массовую долю в материале. В файле заголовка содержаться и другие варианты этой функции. Компилятор сам определяет какая функция имеется в виду по аргументам, которые вы в нее передаете.

Теперь перейдем к созданию геометрии и возвращаемся в функцию Construct(). Мы видим, что первой строчкой вызывается функция InitializeMaterials(). Пропускаем следующие две строчки, они касаются визуализации, и о них мы поговорим отдельно.
Теперь мы находимся на участке кода, который создает мировой объем. Это первое и обязательное, что мы дожны сделать при создании геометрии. Важно, чтобы все другие объемы, которые мы поместим внутрь мирового не выходили за его пределы, иначе программа выдаст ошибку.
    G4Box* world = new G4Box("World", 3*m, 3*m, 3*m);
    G4LogicalVolume *worldLogic = new G4LogicalVolume(world, MaterialMap["Air"], "WorldLogic");
    G4VPhysicalVolume *worldPhys = new G4PVPlacement(0, G4ThreeVector(), worldLogic, "WorldPhys", 0, false, 0);
Первой строчкой мы создаем solid. Это просто форма, которая содержит информацию только о собственном имени "World" и своих линейных размерах. Обратите внимание, что линейные размеры в Geant4 - это полуширины и радиусы. То есть, размер объекта отсчитывается от его центра. Итак, этой строчкой мы создали объект world класса G4Box с именем "World" и размерами 6х6х6 метров. С единицами измерения в Geant4 все просто, они пишутся через звездочку после цифры. Если в начале файла не стоит using namespace CLHEP, то вместо *m мы будем писать *CLHEP::m. CLHEP - файл, а если быть точным namespace, который содаржит определения и взаимосвязи между всевозможными единицами измерения.

Вторая строчка создает логический объем, который содержит информацию о материале, которым он заполнен, своем названии, и главное, содержит указатель на solid. Обратите внимание, что в конструктор класса G4LogicalVolume мы передаем указатель на solid - world. Получается, как будто, вложенная структура. И сейчас мы добавим еще один, третий слой.

G4VPhysicalVolume - класс, который сожержит информацию о расположении логического объема в пространстве, его повороте, материнском логическом объеме (в случае мирового объема - материнского объема нет), своем названии, и еще нескольких других параметрах. Каких - узнайте сами, нажав F2 и перейдя в файл заголовка. И главное, в конструкторе передается указатель на соответствующий ему логический объем. Обратите внимание, что конструктор G4PVPlacement отличасется от названия класса G4VPhysicalVolume. Это связано с тем, что класс G4PVPlacement - наследник класса G4VPhysicalVolume. Такова особенность языка C++. Для понимания этого нюанса вам будет необходимо продвинуться чуть дальше в понимании принципов объектно ориентированных языков и их качества - полиморфизма. Пока давайте просто запомним, что когда мы создаем физический объем, то используем конструктор G4PVPlacement.

Настало время обратиться к рисунку нашего эксперимента и обратить внимание, что весь объем состоит из повторяющихся структур, а именно тонкие листы латуни чередуются с толстыми слоями полиэтилена. Один лист латуни, заключенный между полуслоями полиэтилена составляет один канал. Поясню физический смысл канала. В данном эксперименте на слоистую структуру падал протонный пучок, и заряд, вследствие остановившихся протонов, накапливался в каналах. Лист латуни является проводником и был подключен к амперметру, который регистрировал ток. Такая конструкция наблюдалась в каждом канале. В итоге, к концу эксперимента у нас имелись данные о распределении заряда по глубине.
Начнем с того, что "нарисуем" один лист латуни с полуразмерами 7,5 х 7,5 х 0,00127 см. Вот как выглядел бы этот кусок кода, если бы нам нужно было нарисовать только один лист латуни:
    G4Box* brassSheet = new G4Box("BrassSheet", 7.5*cm, 7.5*cm, 0.00127*cm);
    G4LogicalVolume* brassLogic = new G4LogicalVolume(brassSheet, MaterialMap["Brass"], "BrassLogic");
    G4VPhysicalVolume* brassPhys  = new G4PVPlacement(0, G4ThreeVector(0,0,0), brassLogic, "BrassPhys", worldLogic, false, 0);
Обратите внимание, что вся конструкция полностью аналогична той, с помощью которой мы создавали мировой объем. Единственное отличием является то, что в строчке, где мы создаем физический объем для листа латуни, мы указываем материнский логический объем worldLogic. И еще, G4ThreeVector(0,0,0) и G4ThreeVector() значат одно и то же, вызывают конструктор вектора и создают нулевой вектор. Если мы используем нулевой вектор, то объем создастся в центре нашего мирового объема.
Первое, чем отличается код, который есть в программе от примера, представленного выше - это отсуствием определения типа объекта G4LogicalVolume* во второй строчке. Это связано с тем, что brassLogic является членом класса PolyethyleneDetectorConstruction и уже определен в его заголовке. Принято выделять переменные класса, называя их особенно. Я, например, называю их с большой буквы BrassLogic.
Второе отличие - отсутствие третьей строчки, которая создает физический объем. Нам необходимо сделать сборку повторяющейся структуры (один лист латуни, один лист полиэтилена) и отштамповать ее 65 раз, каждый раз сдвигаясь на ширину одного канала. Делаем мы это с помощью класса G4AssemblyVolume.
    G4AssemblyVolume* channelLogic = new G4AssemblyVolume();
    channelLogic->AddPlacedVolume(BrassLogic, firstPos, 0);
    channelLogic->AddPlacedVolume(CH2Logic, secondPos, 0);
Первая строчка - уже знакомая нам конструкция. Мы инициализируем объект channelLogic класса G4AssemblyVolume. Далее мы создаем "штамп" - добавляем два логических объема, меди и полиэтилена. firstPos и secondPos - это два вектора, отражающих расположение этих двух листов относительно друг друга.
Настало время отштамповать эту структуру 65 раз. Для этого мы создаем цикл:
    for( unsigned int i = 0; i <= 64; i++ )
    {
        G4ThreeVector offset(0, 0, (channelWidth*i));
        channelLogic->MakeImprint(worldLogic, offset, 0);
    }
Внутри цикла первая строчка рассчитывает смещение, вторая - вызвает функцию класса G4AssemblyVolume MakeImprint. Какие аргументы она принимает вы уже умеете выяснять сами.
Предпоследняя строчка в функции Construct() "рисует" последний лист латуни, который выбивается из повторяющегося рисунка. Мы используем только правую сторону из конструкции инициализации физического объема, так как указатель на этот физический объем нам нигде не понадобится. Мы вполне можем написать и целую строчку.

И, наконец, очень важная последняя строчка:

return worldPhys;
Она возвращает указатель на физический мировой объем, как и требует объявление функции Construct() в заголовке класса G4VUserDetectorConstruction:
virtual G4VPhysicalVolume* Construct() = 0;
В заголовке класса PolyethyleneDetectorConstruction:
G4VPhysicalVolume* Construct();
И в файле с кодом класса PolyethyleneDetectorConstruction:
G4VPhysicalVolume* PolyethyleneDetectorConstruction::Construct()
Вот мы и разобрались с тем, как задается геометрия Geant4. Напомню, что мы узнали только азы. Существуют бесконечные возможности создания различных форм, но все они придерживаются той же структуры, что и создание простого кубика. Существуют большое количество вариантов создания сборок и штампования - штампования с измененим размеров и характеристик повторяющейся части. Но, поняв, то что мы сегодня разобрали, вы с помощью собственного желания и гугления сможете разобраться и в этом.

Теперь давайте поговорим о том, как задаются поля. Поля можно создавать какими угодно - однородными или изменяющимися по какому-либо закону, элетрические, магнитные, электро-магнитные, даже гравитационные или сильные. Все зависит от того, что мы заложим в класс поля G4Field, наследуя его.
Но сегодня, мы не будем ударяться в такие сложности (вы сможете в этом разобраться сами, когда понадобится, после того что мы сейчас разберем) и рассмотрим простой случай однородного магнитного поля с использованием стандартного класса G4UniformMagField, который является наследником класса G4Field.
В новом Geant4 10.01 есть очень важное правило. Все описания полей, а так же чувствительных детекторов (до которых мы еще доберемся) выделяются в отдельную функцию ConstructSDandField(). Эта функция тоже пустая в материнском классе G4VUserDetectorConstruction, но не содержит "= 0". Это означает, что ее определять не обязательно. То есть, если нам не нужны магнитные поля или чувствительные детекторы, мы вообще ее не объявляем в нашем классе геометрии.
Сделано это вот зачем. В новой версии Geant4  добавлена возможность многопоточного расчета. Грубо говоря, это возможность раскидать расчет на несколько параллельных вычислений с одной и той же геометрией и условиями. Объект геометрии остается общим для всех потоков. А вот поля и чувствительные детекторы "копируются" для каждого потока, и для каждого потока есть свой собственный объект поля и чувствительного детектора. Это нужно затем, что поля и детекторы активно участвуют в процессе трекинга частицы через геометрию, то есть в рассчете ее траектории. Поэтому для каждого потока, для каждой подзадачи, требуется свой собственный класс поля и детектора.
Функция ConstructSDandField() вызывается каждым потоком отдельно и создает для каждого потока его собственные классы поля и детектора. Если мы не используем многопоточность, то эта функция просто создает класс поля и детектора для нашего эксперимента.
Давайте посмотрим, что содержится в этой функции:

    MagneticField = new G4UniformMagField(G4ThreeVector(100500*gauss,100500*gauss, 0));
    G4FieldManager* fieldMgr = new G4FieldManager(MagneticField);
    BrassLogic->SetFieldManager(fieldMgr, false);
    CH2Logic->SetFieldManager(fieldMgr, false);
    //G4TransportationManager::GetTransportationManager()->SetFieldManager(fieldMgr);
В первой строчке мы создаем объект MagneticField класса G4UniformMagneticField. Обратите внимание, что объект я назвала с большой буквы, так как он является членом класса PolyethyleneDetectorConstruction, и его объявление содержится в заголовке этого класса.
Второй строчкой мы создаем объект fieldMgr класса G4FieldManager. Это класс, который должен содержать указатель на поле, используемое нами. При трекинге частицы, Geant4 обращается к нему.
Теперь у нас есть два варианта. Если мы хотим, чтобы магнитное поле у нас присутствовало только в каком-то логичиском объеме, а не во всем мире, то указатель на G4FieldManager, в который мы передали указатель на наше магнитное поле, мы передаем только  в нужный логический объем. Тогда этот FieldManager не является главным, а действует только в внутри объема, который соджержит на него указатель. (В программе может быть несколько объектов класса G4FieldManager). Попробуйте разные величины магнитного поля и запустите программу. Вы увидите, что треки протонов загибаютя по разному. А при значении магнитного поля больше 100000 Гаусс, протоны начинают вылетать из объема сбоку.
Теперь, если мы хотим задать магнитное поле во всем мировом объеме, то объект класса G4FieldManager, содержащий указатель на это магнитное поле нужно сделать главным. То есть передать в G4TransportationManager - static объект, который управляет прохождением частицы через геометрию. Этот объект единственный во всей программе и указатель на него мы получаем уже знакомым нам способом. Раскомментьте эту строчку и закоментьте две предыдущие. Запустите программу. Теперь вы видите, что магнитное поле действует во всем объеме.

Практическое задание:
Нарисуйте аналогичную геометрию эксперимента из статьи, которую вы сможете найти здесь.

Sunday, March 8, 2015

Скачивание кода примера из GitHub

Этот и последующие примеры, которые мы будем использовать на занятиях содержатся в моем аккакунте на GitHub. Это веб-сервис для хостинга IT-проектов и их совместной разработки. Он основан на системе контроля версий Git, которую мы сейчас и установим на на наш Linux Mint. Итак, начинаем:

  • Открываем командную строку и пишем уже знакомую конструкцию, которая устанавливает нам Git. 
sudo apt-get install git

  • Теперь заходим в домашнюю директорию и загружаем код примера из моего аккаунта на GitHub по тэгу "Example*". Вместо звездочки ставим номер примера, который нам нужен.
cd ~/
git clone https://github.com/ASMcArrow/Polyethylene.git

cd Polyethylene
git checkout tags/Example1

  • Готово! Теперь в домашней директории появится новая папка с примером.

Friday, February 27, 2015

Занятие 1. Установка Geant4 10.01 на платформу Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit)

Дорогие читатели!

В этой статье содержатся весьма специфические рекомендации по установке виртуальной машины с помощью VMware Player 6.0.5, установке на нее указанного в названии Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit), затем установке Geant4 10.01 (самый свежий релиз на сегодняшнюю дату). Такая строгая привязка в версиям программного обеспечения следует из огромного диапазона ошибок и проблем, возникающих при установке Geant4. Обратите внимание - для успешного проведения всех процедур необходимо стабильное подключение к интернету!
  • Установка виртуальной машины на Windows 7/8 и установка на нее Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit)
  • Скачиваем образ диска с Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit) отсюда.
  • Скачиваем бесплатную версию VMware Player 6.0.5 отсюда по первой ссылке из списка. Устанавливаем со стандартными настройками.
  • Открываем VMware Player 6.0.5 и выбираем "File -> New Virtual Machine...". Откроется wizard, в котором мы делаем следующее: Выбираем "Typical" -> Выбираем "Installer disc image file"; Указываем путь до образа диска с Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit), который мы скачали до этого -> Выбираем "Linux"; Выбираем версию "Ubuntu" -> В верхнем поле вводим название нашей виртуальной машины по своему выбору -> Выбираем объем жесткого диска, который мы готовы выделить под систему (желательно, не меньше 10 Гб)  -> По желанию, можно поменять параметры системы. Например, изменить выделяемый объем оперативной памяти. Минимальный допустимый ее объем - 512 Мб; Жмем "Finish".
  • Возвращаемся в главное окно VMware Player 6.0.5, выбираем в списке нашу виртуальную машину и жмем "Power on this virtual machine". Ждем, пока система загрузится, на все всплывающие окна жмем "OK". Возможно, снизу появится желтое всплывающее окно, которое будет просить указать момент, когда мы закончили установку и система перезагрузилась. Пока его не трогаем.
  • Загрузился LiveCD, это пробная версия системы. Саму систему мы пока не установили. На рабочем столе запускаем "Install Linux Mint".
  • Далее идет достаточно очевидная установка Linux Mint. Никаких параметров, установленных по умолчанию, не меняем. Язык системы и раскладку клавиатуры я выбрала "English(US)".
  • После того как установка завершится, и система перезагрузится, нажмите в желтом окне снизу "I Finished Installing". 
  • С первым этапом покончено!

  • Установка Geant4 10.01 на Linux Mint 17.1 "Rebecca" - Cinnamon (32-bit)
Перед тем, как мы начнем сборку и установку Geant4 я приведу несколько необходимых команд для командной строки в Linux и упрощенно поясню что они значат.
  1. sudo  Команда, котороя, по сути, дает нам права администратора. Когда операция затрагивает системные папки (такими операциями является инсталлирование из репозитория (см. ниже) и инсталлирование собранной бииблиотеки, редактирование системных файлов и т.д.), нам необходимы такие права. sudo используется как приставка перед командой, которую мы хотим выполнить, например sudo make install.
  2. ls Команда, которая выводит на экран содержимое директории, в которой мы сейчас находимся. Это полезно, чтобы убедиться, что мы находимся там, где нужно. Кроме того в Linux есть и нормальный проводник, почти ничем не отличающийся от того, что в Windows. Его эмблему - папку - вы можете увидеть на рабочей панели внизу экрана.
  3. cd Команда перехода в другую директорию. После этой команды через пробел указывается путь до директории, в которую вам нужно. Путь можно указывать как относительно директории, где вы сейчас находитесь, так и абсолютный. Например, пусть вы находитесть в папке Documents: ~/Documents/MyStuff - абсолютный путь. В нем для обозначения домашней директории используется знак ~, который эквивалентен /home/имя_вашего_компьютера/. Можно писать и так, и так. Имя вашего компьютера вы выбрали в момент установки Linux Mint. Итак, просто cd /MyStuff, тоже будет работать, и этот путь называется относительным.  Еще стоит упомянуть знак ../, он означает обращение к папке, стоящей выше по дереву. Скажем, чтобы из папки Documents перейти на директорию выше (это наша домашняя директория) пишем к командной строке cd ../
  4. mkdir Создает папку. Тут все просто. После этой команды через пробел указывается название будущей директории.
  5. apt-get install имя_библиотеки Команда, которую мы будем использовать, чтобы установить необходимые нам дополнительные библиотеки из удаленного репозитория через интернет.
  6. nano Команда, открывающая простой текстовый редактор, прямо в консоли. Он уже идет вместе с Linux. Чтобы сохранить файл: Ctrl+X -> Y -> Enter.
  7. ccmake путь_до_папки_с_исходниками Команда, которая вызывает интерактивную версию утилиты cmake, которая нам нужна, чтобы настроить параметры библиотеки Geant4, необходимые нам.
  8. source - команда, которая запускает выполнение скрипта для консоли. Скрипт для консоли или иногда его называют shell script - это файл состоящий из команд, каждая из которых может быть запущена в консоли напрямую. Скажем, этот файл может содержать команды cd или mkdir. Такие файлы могут иметь расширение sh, как, например, в нашем случае файл geant4make.sh (см. ниже). В принципе, мы можем запустить скрипт и просто напечатав ./geant4make.sh , но тогда все изменения, которые мы с его помощью сделали в консоли не будут видны. Файл скрипта обязательно содержит первую строку, открывающую свою отдельную консоль, которая потом закрывается и исчезает. Чтобы передать изменения именно в нашу рабочую консоль, в которой наша командная строка, необходимо использовать команду source. 
  9. chmod +x имя_файла - команда, которая дает всем пользователям право запуска указанного файла. Часто бывает что система Linux ограничивает такие права, часто для файлов, скачанных из интернета.
 Итак, приступим к установке Geant4 10.01.
  • Сначала нам необходимо установить библиотеки, от которых зависит Geant4 10.01. Устанавливать их будем из репозитория, удаленного хранилища библиотек и программ для нашей версии Linux. Установка всех указанных ниже библиотек производится одной и той же строкой, указанной ниже. При первой из установок sudo попросит у вас пароль, который вы выбрали при установке Linux. При начале установки командная строка может вас спросить действительно ли вы хотите установить столько-то мегабайт - жмете "y" и Enter. Ждете, пока вам не вернется командная строка. Затем устанавливаете следующую библиотеку.
sudo apt-get install имя_библиотеки
  • Библиотеки, которые надо установить:
qt4-default - дистрибутив qt4, интерфейсной библиотеки.
libqt4-opengl-dev - дистрибутив, отвечающий за взаимодействие Qt4 и OpenGL, библиотеки, отвечающей за визуализацию. Сам OpenGL уже установлен в Linux Mint с самого начала.
build-essential - пакет, содержащий необходимый нам компилятор g++.
cmake - программа, необходимая для конфигурирования библиотеки Geant4 под наши нужды (см. ниже).
cmake-curses-gui - дополнение к cmake, позволяющее редактировать параметры библиотеки интерактивно. Вызывается с помощью команды ccmake.
libexpat1-dev - библиотека, необходимая для работы с XML форматом. Возможно, это формат данных в котором представлены таблицы сечений, тормозных способностей, материалов, изотопов и прочее, что попадает под отпределение data в Geant4.
libxmu-dev - библиотека, необходимая для поддержки X11, оконной системы, обеспечивающей стандартные инструменты и протоколы для построения графического интерфейса то есть графической оболочки Linux, которая показывает нам окна, рабочие столы и прочие красоты.
  • После того, как мы установили все вышеуказанные библиотеки, скачиваем исходники библиотеки Geant4 10.01 отсюда. Выбираем самый верхний "Download". Находим через проводник куда скачалось, открываем архив (все подхватывает линуксовый распаковщик) и распаковываем в папку "Documents". Теперь у нас там появилась папка "geant4.10.01".
  • Открываем консоль. Заходим оттуда в папку "Documents" и создаем папку "geant4.10.01-build".
cd ~/Documents
mkdir geant4.10.01-build
cd geant4.10.01-build
  • Запускаем ccmake. Откроется его окно в консоли, пока пустое. Жмем "с". Запускается конфигурация, и появляются параметры, которые нам интересны.
ccmake ../geant4.10.01
  • Теперь нам нужно настроить некоторые параметры. Это делается стрелками и Enter.
  1. Меняем параметр "GEANT4_BUILD_MULTITHREADED" на "ON". Это позволит нам собрать многопоточную версию Geant4. Использованию этой особенности будет посвящено отдельное занятие.
  2. Меняем параметр "GEANT4_INSTALL_DATA" на "ON". Это позволит подкачать из интернета необходимые таблицы сечений и изотопов при сборке библиотеки.
  3. Меняем параметр "GEANT4_USE_OPENGL_X11" на "ON". Мы будем пользоваться OpenGL для визуализации.
  4. Меняем параметр "GEANT4_USE_QT" на "ON". Мы будем пользоваться интерфейсной библиотекой Qt для интерактивных задач.
  • Далее жмем "c" пока все звездочки рядом с параметрами не исчезнут. Это значит, что все наши изменения отражены в конфигурационном файле. После этого жмем "g" - сгенерировать Makefile - файл, который управляет сборкой.
  • Перед тем, как мы нажмем "g" окно cmake должно представлять из себя следующее.

  • Теперь мы готовы запустить компиляцию библиотеки. В командной строке набираем make c параметром -j, сразу после которого следует цифра количества потоков, в которых будет собираться библиотека. Количество потоков не должно превышать количество виртуальных ядер на вашем компьютере. Если не знаете таких параметров своего процессора, просто пишите make. Итак, запускаем и идем пить чай. Сборка займет некоторое время, от получаса.
make -j8
  • После того, как сборка закончится, запускаем инсталляцию. При этом инсталляция будет проходить в папку, которая указана в параметре "CMAKE_INSTALL_PREFIX". В нашем случае папка системная, поэтому требуется sudo.
sudo make install


  • Сборка (компиляция) и запуск примера B1
  • Переходим в папку с примером B1, который поставляется вместе с исходниками Geant4. Проводим в точности те же самые процедуры, что и при установке Geant4.
cd ../geant4.10.01/examples/basic/mkdir B1-build
cd B1-build
ccmake ../B1
  • При вызове cmake у нас откроется окно с параметрами примера. В них нужно всего одно изменение. В параметр "CMAKE_BUILD_TYPE" вписать "Release".  Дальше все как обычно: c -> c -> g.
  • Дальше следуем стандартной процедуре. Инсталлировать примеры не нужно.
make
  • Настало время запустить пример! Но для этого нам необходимо сделать еще один маленький шаг, а именно запустить скрипт, который укажет нашей системе путь до библиотеки, Qt и необходимых таблиц данных. Вот что мы пишем в командной строке:
source ~/Documents/geant4.10.01-build/geant4make.sh
  • Теперь мы готовы запустить пример. Набираем и наслаждаемся.
./exampleB1


  • Делаем все еще удобней или настройка Qt Creator
  • Скачиваем среду разработки Qt Creator 3.3.1 for Linux/X11 здесь. Эта среда разработки под C++, которая позволит нам очень удобно работать с нашими будущими программами.
  • Устанавливаем Qt Creator 3.3.1 for Linux/X11 следующим образом. В командной строке набираем:
chmod +x ~/Downloads/qt-creator-opensource-linux-x86-3.3.1.run
~/Downloads/qt-creator-opensource-linux-x86-3.3.1.run
  • Установка не должна вызывать сложностей. Никаких особых настроек там не нужно.
  • Теперь возвращаемся на рабочий стол, жмем правую кнопку мыши. "Create New Document -> Empty Document". Переименовываем его в "myqtcreator.sh".
  • Мы собираемся написать свой shell script, который будет передавать в Qt Creator все нужные нам настройки из скрипта geant4make.sh. Иначе эта среда разработки не будет видеть Geant4. Нам нужно показать где все находится.
  • Итак, открываем файл и пишем в нем буквально следующее:
#!/bin/bash
source ~/Documents/geant4.10.01-build/geant4make.sh
~/qtcreator-3.3.1/bin/qtcreator.sh
  • Что делает этот скрипт. Первая строчка стандартна и обязательна для всех shell scripts. В этой строке после #! указывается путь к bash-интерпретатору. bash-интерпретатор это код, который преобразует наши команды, такие как ls, mkdir в команды, понятные процессору. 
  • Следующая строчка запускает уже известный нам скрипт geant4make.sh
  • Последняя строчка запускает скрипт, который у нас появился после установки Qt Creator. Он нам запускает Qt Creator.
  • Теперь кликаем дважды на файл, который мы создали. Выбираем "Run". У нас загрузился Qt Creator. Теперь мы можем открыть в нем наш пример B1. С ним будет удобно работать, так как весь синтаксис будет подсвечиваться, будет легко переключаться между файлами, а компилировать и запускать пример можно будет просто нажатием на кнопку.
  • После того как загрузился Qt Creator жмем "File -> Open File of Project... -> Навигируем до папки с примером B1, которая находится в дистрибутиве Geant4. В папке B1 выбираем файл CMakeLists.txt (что это такое рассмотрим на следующем занятии) -> Open.
  • Затем называем папку, в которой будет содержаться сборка этого примера, сделанная Qt Creator, скажем B1-build-creator. Жмем "Next -> Run CMake -> Finish".
  • Теперь мы видим слева все дерево файлов, которые содержатся в этой папке. Пощелкайте по ним и посмотрите на код. Обратите внимание, что функции и переменные выделены разными цветами.
  • Настало время сборки. Жмем на изображение молотка в левом нижнем углу окна. Наслаждаемся. Это действие равносильно команде make в командной строке.
  • Теперь жмем на зеленый треугольник. Мы запускаем программу. Наслаждаемся еще больше. Готово!