Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CIBenchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ jobs:
source bin/setup.MaCh3.sh
source bin/setup.MaCh3Tutorial.sh

pprof ./bin/MCMCTutorial ${{ matrix.outpath }}/MaCh3Tutorial --focus="RunMCMC" --pdf > ${{ matrix.outpath }}/${{ matrix.title }}.pdf
pprof ./bin/${{ matrix.app }} ${{ matrix.outpath }}/MaCh3Tutorial --focus="RunMCMC" --pdf > ${{ matrix.outpath }}/${{ matrix.title }}.pdf

- name: Push Plot to gh-benchmarks Branch
run: |
Expand Down
2 changes: 1 addition & 1 deletion CIValidations/MaCh3CLI
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ run_multicanoical_validations() {
mkdir ${MaCh3Tutorial_ROOT}/outputs/
mkdir ${MaCh3Tutorial_ROOT}/outputs/plotting/

${MaCh3Tutorial_ROOT}/bin/MCMCTutorial TutorialConfigs/FitterConfig.yaml General:MCMC:Multicanonical:Enabled:True General:OutputFile:umbrella/umbrellafile0.root
${MaCh3Tutorial_ROOT}/bin/MCMCTutorial TutorialConfigs/FitterConfig.yaml -o General:MCMC:Multicanonical:Enabled:True -o General:OutputFile:umbrella/umbrellafile0.root

# Create umbrellafile1.root ... umbrellafile59.root
for i in $(seq 1 59); do
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ add_subdirectory(CIValidations)
add_subdirectory(Tutorial)
add_subdirectory(SplinesTutorial)
add_subdirectory(SamplesTutorial)
add_subdirectory(MaCh3Plugins)

# MOVE THIS BLOCK HERE - BEFORE add_subdirectory(python)
# After MaCh3 is added/found, determine MaCh3_PREFIX
Expand Down
37 changes: 37 additions & 0 deletions MaCh3Plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
add_custom_target(TutorialPlugins)

foreach(app
MCMCTutorialPlugin
)

add_library(${app} SHARED ${app}.cpp)

target_link_libraries(${app} PRIVATE MaCh3Tutorial::SamplesTutorial MaCh3::All)
# target_include_directories(${app} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>)

target_include_directories(${app}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)

install(
TARGETS ${app}
EXPORT MaCh3TutorialTargets
LIBRARY DESTINATION lib
)

install(
FILES ${app}.hpp
DESTINATION include/Mach3Plugins
)

add_library(MaCh3Tutorial::${app} ALIAS ${app})

# add_executable(${app} ${app}.cpp)
# target_link_libraries(${app} MaCh3Tutorial::ValidationsUtils MaCh3Tutorial::SamplesTutorial)

# add_dependencies(TutorialApps ${app})
# install(TARGETS ${app} DESTINATION bin)
endforeach(app)

70 changes: 70 additions & 0 deletions MaCh3Plugins/MCMCTutorialPlugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// MaCh3 includes
#include "Manager/MaCh3Logger.h"
#include "Fitters/MaCh3Factory.h"
#include "SamplesTutorial/SampleHandlerTutorial.h"
#include "MaCh3Plugins/MCMCTutorialPlugin.hpp"

namespace M3{

MaCh3ArgumentParser* MCMCTutorialPlugin::get_parser(){
m_parser = std::make_unique<MaCh3ArgumentParser>("tutorial", "1.0", argparse::default_arguments::help);
m_parser->add_argument("config")
.help("Config file.")
.metavar("CONFIG")
.required();
m_parser->add_argument("--MCMCSteps")
.scan<'d', int>()
.help("specify the number of steps.");
m_parser->add_argument("-o", "--override")
.append()
.help("specify any config overrides.");
return m_parser.get();
}

int MCMCTutorialPlugin::Run(){
std::string config = m_parser->get<std::string>("config");

std::vector<std::string> args = { m_parser->name(), config };

if (auto fn = m_parser->present<int>("--MCMCSteps")) {
args.push_back("General:MCMC:NSteps:" + std::to_string(*fn));
}

std::vector<std::string> overrides = m_parser->get<std::vector<std::string>>("--override");
for (const std::string& override_str : overrides) {
args.push_back(override_str);
}

// Convert to char* array
std::vector<char*> argv;
argv.reserve(args.size());
for (auto& s : args)
argv.push_back(s.data());

// Initialise manger responsible for config handling
auto FitManager = MaCh3ManagerFactory(argv.size(), argv.data());

// Initialise covariance class reasonable for Systematics
auto xsec = MaCh3CovarianceFactory<ParameterHandlerGeneric>(FitManager.get(), "Xsec");

// Initialise samplePDF
auto SampleConfig = Get<std::vector<std::string>>(FitManager->raw()["General"]["TutorialSamples"], __FILE__ , __LINE__);
auto mySamples = MaCh3SampleHandlerFactory<SampleHandlerTutorial>(SampleConfig, xsec.get());

// Create MCMC Class
std::unique_ptr<FitterBase> MaCh3Fitter = MaCh3FitterFactory(FitManager.get());
// Add covariance to MCM
MaCh3Fitter->AddSystObj(xsec.get());
for (size_t i = 0; i < SampleConfig.size(); ++i) {
MaCh3Fitter->AddSampleHandler(mySamples[i]);
}
// Run MCMCM
MaCh3Fitter->RunMCMC();

for (size_t i = 0; i < SampleConfig.size(); ++i) {
delete mySamples[i];
}
return 0;
}

};
18 changes: 18 additions & 0 deletions MaCh3Plugins/MCMCTutorialPlugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "CLI/API/plugin.hpp"

namespace M3{

class MCMCTutorialPlugin: public PluginBase{

public:
virtual ~MCMCTutorialPlugin() = default;

MaCh3ArgumentParser* get_parser();

int Run();

};

};

MACH3_REGISTER_PLUGIN(M3::MCMCTutorialPlugin)
67 changes: 50 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,14 @@ And get some reference values from other users, this can look something like:
By comparing rates for each sample much what other users observe you can very simply ensure you correctly setup MaCh3.

## How to run MCMC
To run MCMC simply
To run MCMC simply:
```bash
./bin/MCMCTutorial TutorialConfigs/FitterConfig.yaml
mach3 tutorial TutorialConfigs/FitterConfig.yaml
```

> [!NOTE]
> The `mach3` CLI is new, and not every executable in this tutorial has been integrated into it yet. If you have any issues or feedback, please contact the developers or raise issues on this GitHub repository or the MaCh3 GitHub repository.

Congratulations! 🎉
You have just finished your first MCMC chain. You can view `Test.root` for example in TBrowser like in plot below.

Expand All @@ -146,33 +150,62 @@ General:
```
and then re-running `MCMCTutorial`.

**Warning**: If you modified files in the main `MaCh3Tutorial` folder instead of `build`, you will have to call `make install` for the changes to propagate! Generally speaking, it is good practice to work from the `build` directory and make your config changes there so that local changes do not have to be tracked by git.
> [!WARNING]
> If you modified files in the main `MaCh3Tutorial` folder instead of `build`, you will have to call `make install` for the changes to propagate! Generally speaking, it is good practice to work from the `build` directory and make your config changes there so that local changes do not have to be tracked by git.

### Config Overrides
Instead of changing the config file `TutorialConfigs/FitterConfig.yaml` above directly, you can instead dynamically override your configurations at the command line like this:
```bash
./bin/MCMCTutorial TutorialConfigs/FitterConfig.yaml General:MCMC:NSteps:100000
mach3 tutorial TutorialConfigs/FitterConfig.yaml --override General:MCMC:NSteps:100000
```
In this way, you can add as many configuration overrides here as you like, as long as the format is `[executable] [config] ([option1] [option2] ...)`.
You can also use the short form `-o` instead of `--override`. You can add as many configuration overrides here as you like: `[executable] [config] (-o [option1] -o [option2] ...)`.

> [!WARNING]
> This overriding process is only possible for the "main config" (i.e., configs that respond directly to the `Manager` class in MaCh3 core).
> This main config is used with the apps in the `Tutorial` folder here; for the other apps (mainly plotting apps like `PredictivePlotting`)
> that read from `bin/TutorialDiagConfig.yaml`, this is not possible,
> as further command line arguments are interpreted as *input ROOT files*, not override directives.
>
> [!WARNING]
> The format required for overriding is different for the executables described later on in this tutorial which have not been integrated into the `mach3` CLI.
> For those executables, the `--override` option is not needed, simply write the settings you want to override as arguments at the end of the command.
> For example `./bin/PredictiveTutorial TutorialConfigs/FitterConfig.yaml General:OutputFile:PriorPredictiveOutputTest.root`.

**Warning** This overriding process is only possible for the "main config" (i.e., configs that respond directly to the `Manager` class in MaCh3 core). This main config is used with the apps in the `Tutorial` folder here;
for the other apps (mainly plotting apps like `PredictivePlotting`) that read from `bin/TutorialDiagConfig.yaml`, this is not possible, as further command line arguments are interpreted as *input ROOT files*, not override directives.
If you're lucky, the setting you plan to override may have an explicit option in `mach3 tutorial`. To find out run `mach3 tutorial --help`:
```console
Usage: mach3 tutorial [--help] [--MCMCSteps VAR] [--override VAR]... CONFIG

Positional arguments:
CONFIG Config file. [required]

Optional arguments:
-h, --help shows help message and exits
--MCMCSteps specify the number of steps.
-o, --override specify any config overrides. [may be repeated]
```
You can see the `--MCMCSteps` option, so earlier we could have instead written:
```bash
mach3 tutorial TutorialConfigs/FitterConfig.yaml --MCMCSteps 100000
```

### Processing MCMC Outputs
Being able to visualise and analyse the output of the MCMC is standard procedure after a chain has finished. MaCh3 uses `ProcessMCMC` to transform the raw output from the MCMC into smaller outputs that are more easily digested by downstream plotting macros. You can run it using
Being able to visualise and analyse the output of the MCMC is standard procedure after a chain has finished. MaCh3 uses `mach3 process` (previously `ProcessMCMC`) to transform the raw output from the MCMC into smaller outputs that are more easily digested by downstream plotting macros. You can run it using
```bash
./bin/ProcessMCMC bin/TutorialDiagConfig.yaml Test.root
mach3 process bin/TutorialDiagConfig.yaml Test.root
```
where `Test.root` is the output of running `MCMCTutorial` as described [here](#how-to-run-mcmc). You can find some quickly-generated plots in `Test_drawCorr.pdf`. One of plots you will encounter is:
where `Test.root` is the output of running `mach3 tutorial` as described [here](#how-to-run-mcmc). You can find some quickly-generated plots in `Test_drawCorr.pdf`. One of plots you will encounter is:

<img width="350" alt="Posterior example" src="https://github.com/user-attachments/assets/1073a76e-5d82-4321-8952-e098d1b0717f">

This is the marginalised posterior of a single parameter. This is the main output of the MCMC.

There are many options in `ProcessMCMC` that allow you to make many more analysis plots from the MCMC output; we recommend that you see [here](https://mach3-software.github.io/MaCh3/BayesianAnalysis.html) to get better idea what each plot means. In particular, we recommend comparing 2D posteriors with the correlation matrix, and playing with triangle plots.
There are many options in `mach3 process` that allow you to make many more analysis plots from the MCMC output; we recommend that you see [here](https://mach3-software.github.io/MaCh3/BayesianAnalysis.html) to get better idea what each plot means. In particular, we recommend comparing 2D posteriors with the correlation matrix, and playing with triangle plots.

> [!TIP]
> Some of those option are immediately available in the command line, find out which ones with `mach3 process --help`.

### Plotting MCMC Posteriors
Once you have the processed MCMC output from `ProcessMCMC`, which will be called something like `<inputName>_Process.root`, you can make fancier analysis plots from it using the `GetPostfitParamPlots` app like:
Once you have the processed MCMC output from `mach3 process`, which will be called something like `<inputName>_Process.root`, you can make fancier analysis plots from it using the `GetPostfitParamPlots` app like:

```bash
./bin/GetPostfitParamPlots Test_drawCorr.root
Expand All @@ -191,14 +224,14 @@ The output should look like plot below. This conveys same information as the ind
<img width="350" alt="Ridge" src="https://github.com/user-attachments/assets/617f5929-b389-495e-ab7b-2ecd6c2d991e">

**Violin Plot** - This also allow to see nicely non-Gaussian parameters but also is useful in comparing two chains.
`ProcessMCMC` must be run with option "PlotCorr" to be able to produce violin plot.
`mach3 process` must be run with option "--corr" to be able to produce violin plot.

<img width="350" alt="Violin example" src="https://github.com/user-attachments/assets/4788ab29-f24a-4b09-8b0f-c9b36d069cfe">

</details>

### Plotting Correlation Matrix
If you have run `ProcessMCMC` with option "PlotCorr" you will have a correlation matrix in the outputs. This is a handy tool for viewing how correlated different parameters are.
If you have run `mach3 process` with option "-corr" you will have a correlation matrix in the outputs. This is a handy tool for viewing how correlated different parameters are.
However, mature analyses with hundreds of parameters may run into the problem of having too large of plots to be useful. To combat this, you can plot a subset of parameters using `MatrixPlotter`:
```bash
./bin/MatrixPlotter bin/TutorialDiagConfig.yaml Test_drawCorr.root
Expand Down Expand Up @@ -317,7 +350,7 @@ Congratulations, you have successfully modified the MCMC! 🎉
### How to Compare Chains
Now that you have two chains you can try comparing them using the following:
```bash
./bin/ProcessMCMC bin/TutorialDiagConfig.yaml Test.root Default_Chain Test_Modified.root Modified_Chain
mach3 process bin/TutorialDiagConfig.yaml Test.root Default_Chain Test_Modified.root Modified_Chain
```
This will produce a pdf with plots showing overlayed posteriors from both chains. Most should be similarly except modified parameter.

Expand Down Expand Up @@ -426,7 +459,7 @@ You can also easily change what variable the sample is binned in to get slightly
```
You can run the MCMC again using this new configuration (after changing the output file name again!), and then compare all 3 chains using:
```bash
./bin/ProcessMCMC bin/TutorialDiagConfig.yaml Test.root Default_Chain Test_Modified.root Modified_Chain Test_Modified_Sample.root ModifiedSameple_Chain
mach3 process bin/TutorialDiagConfig.yaml Test.root Default_Chain Test_Modified.root Modified_Chain Test_Modified_Sample.root ModifiedSameple_Chain
```

<details>
Expand Down Expand Up @@ -621,7 +654,7 @@ The latter class deals with actual event reweighting and general heavy lifting.
## MCMC Diagnostic
A crucial part of MCMC is diagnosing whether a chain has converged or not. You can produce chain diagnostics by running:
```bash
./bin/DiagMCMC Test.root bin/TutorialDiagConfig.yaml
mach3 diag Test.root bin/TutorialDiagConfig.yaml
```
This will produce a plethora of diagnostic information. One of most important of these are the autocorrelations for each of the parameters. Autocorrelation indicates how correlated MCMC steps are when they are n-steps apart in the chain.
Generally speaking, we want the autocorrelation to drop to 0 fast and stay around there (like in the plot below). You can read about other diagnostics [here](https://mach3-software.github.io/MaCh3/MCMCconvergance.html), but it is sufficient for now to focus on autocorrelation.
Expand Down
17 changes: 16 additions & 1 deletion Tutorial/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
add_custom_target(TutorialApps)

foreach(app
MCMCTutorial
LLHScanTutorial
PredictiveTutorial
SigmaVarTutorial
Expand All @@ -20,6 +19,22 @@ foreach(app
install(TARGETS ${app} DESTINATION bin)
endforeach(app)

foreach(plugin_app
MCMCTutorial
)
add_executable(${plugin_app} ${plugin_app}.cpp)
target_link_libraries(${plugin_app} MaCh3Tutorial::${plugin_app}Plugin MaCh3Tutorial::ValidationsUtils MaCh3Tutorial::SamplesTutorial)
add_dependencies(${plugin_app} ${plugin_app}Plugin) # must be real target, not alias
if(MaCh3Tutorial_PROFILING_ENABLED)
target_link_libraries(${plugin_app}
profiler # Add this line to link gperftools
)
endif()

add_dependencies(TutorialApps ${plugin_app})
install(TARGETS ${plugin_app} DESTINATION bin)
endforeach(plugin_app)

install(FILES
TutorialDiagConfig.yaml
DESTINATION ${CMAKE_BINARY_DIR}/bin)
40 changes: 13 additions & 27 deletions Tutorial/MCMCTutorial.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
// MaCh3 includes
#include "Fitters/MaCh3Factory.h"
#include "SamplesTutorial/SampleHandlerTutorial.h"
#include "Manager/MaCh3Logger.h"
#include "MaCh3Plugins/MCMCTutorialPlugin.hpp"

int main(int argc, char *argv[]) {
// Initialise manger responsible for config handling
auto FitManager = MaCh3ManagerFactory(argc, argv);

// Initialise covariance class reasonable for Systematics
auto xsec = MaCh3CovarianceFactory<ParameterHandlerGeneric>(FitManager.get(), "Xsec");

// Initialise samplePDF
auto SampleConfig = Get<std::vector<std::string>>(FitManager->raw()["General"]["TutorialSamples"], __FILE__ , __LINE__);
auto mySamples = MaCh3SampleHandlerFactory<SampleHandlerTutorial>(SampleConfig, xsec.get());

// Create MCMC Class
std::unique_ptr<FitterBase> MaCh3Fitter = MaCh3FitterFactory(FitManager.get());
// Add covariance to MCM
MaCh3Fitter->AddSystObj(xsec.get());
for (size_t i = 0; i < SampleConfig.size(); ++i) {
MaCh3Fitter->AddSampleHandler(mySamples[i]);
}
// Run MCMCM
MaCh3Fitter->RunMCMC();

for (size_t i = 0; i < SampleConfig.size(); ++i) {
delete mySamples[i];
}
return 0;
int main(int argc, char const* argv[]) {
MACH3LOG_WARN("Deprecation Warning: Use of the standalone executable will be deprecated in future releases.");
MACH3LOG_WARN(" : you can use 'mach3 tutorial' as a direct replacement instead.");
argv[0] = "tutorial";
M3::MCMCTutorialPlugin tutorial;
ArgumentParser* parser = tutorial.get_parser();
parser->parse_args(argc, argv);
tutorial.Run();
MACH3LOG_WARN("Deprecation Warning: Use of the standalone executable will be deprecated in future releases.");
MACH3LOG_WARN(" : you can use 'mach3 tutorial' as a direct replacement instead.");
return 0;
}
2 changes: 2 additions & 0 deletions cmake/Templates/setup.MaCh3Tutorial.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,6 @@ else
fi
fi

export MACH3_PLUGINS=${SETUPDIR}/MaCh3Plugins

unset SETUPDIR
Loading