File indexing completed on 2026-10-09 08:30:26
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Mille/MillePedeSolver.hpp"
0010
0011 #include "Acts/Utilities/Logger.hpp"
0012 #include "Acts/Utilities/Result.hpp"
0013 #include "ActsPlugins/Mille/MillePedeError.hpp"
0014
0015 #include <filesystem>
0016 #include <fstream>
0017 #include <sstream>
0018 #include <string>
0019 #include <tuple>
0020
0021 #include "detail/RunSolverProcess.hpp"
0022
0023 namespace {
0024
0025 ActsPlugins::MillePedeSolver::ExitStatus interpretExit(int theExitCode) {
0026 using enum ActsPlugins::MillePedeSolver::ExitStatus;
0027
0028
0029 if (theExitCode < 0) {
0030 return NotFinishedOrCrashed;
0031 } else if (theExitCode == 0) {
0032 return NominalExit;
0033 } else if (theExitCode == 1) {
0034 return TolerableWarnings;
0035 } else if (theExitCode <= 4) {
0036 return SeriousWarnings;
0037 } else if (theExitCode == 5) {
0038 return NoSolution;
0039 } else {
0040 return Aborted;
0041 }
0042 }
0043
0044 std::tuple<int, ActsPlugins::MillePedeSolver::ExitStatus, std::string>
0045 readDetailedExit(const std::filesystem::path& mpend) {
0046 std::ifstream exitCodeFile(mpend);
0047 std::string statusMessage = "";
0048 int retCode = 0;
0049
0050 exitCodeFile >> retCode;
0051
0052 std::stringstream remainingCont;
0053 remainingCont << exitCodeFile.rdbuf();
0054 statusMessage = remainingCont.str();
0055 statusMessage = statusMessage.substr(statusMessage.find_first_not_of(' '));
0056 statusMessage =
0057 statusMessage.substr(0, statusMessage.find_last_not_of(" \n") + 1);
0058 exitCodeFile.close();
0059
0060 ActsPlugins::MillePedeSolver::ExitStatus status = interpretExit(retCode);
0061 return {retCode, status, statusMessage};
0062 }
0063
0064 std::filesystem::path copyIfRequested(
0065 const std::filesystem::path& originalLoc,
0066 const std::optional<std::filesystem::path>& userLoc,
0067 const Acts::Logger& logger) {
0068 if (!std::filesystem::exists(originalLoc)) {
0069 return "";
0070 }
0071 if (!userLoc.has_value()) {
0072 return originalLoc;
0073 }
0074 if (!std::filesystem::copy_file(
0075 originalLoc, *userLoc,
0076 std::filesystem::copy_options::overwrite_existing)) {
0077 ACTS_WARNING(" Failed to copy output file " << originalLoc << " to "
0078 << *userLoc);
0079 return originalLoc;
0080 }
0081 return *userLoc;
0082 }
0083
0084 }
0085
0086 namespace ActsPlugins {
0087
0088 Acts::Result<MillePedeSolver::Result> MillePedeSolver::solve(
0089 const Config& cfg) const {
0090 ACTS_INFO("=== Proceeding to run Millepede-II alignment fit ===");
0091
0092
0093 std::filesystem::path workDir =
0094 cfg.workDir.value_or(std::filesystem::current_path());
0095
0096
0097 if (!std::filesystem::exists(workDir)) {
0098 std::filesystem::create_directories(workDir);
0099 }
0100
0101 ACTS_DEBUG("Will run the alignment fit in folder '"
0102 << std::filesystem::absolute(workDir) << "'");
0103
0104
0105 std::vector<std::string> mpArgs = cfg.extraOpts;
0106
0107 if (std::filesystem::path steerPath = cfg.steeringFile; !steerPath.empty()) {
0108 if (steerPath.is_relative()) {
0109 steerPath = std::filesystem::current_path() / steerPath;
0110 }
0111 if (!std::filesystem::exists(steerPath)) {
0112 ACTS_ERROR("Steering file " << steerPath
0113 << " does not seem to exist - aborting!");
0114 return Acts::Result<Result>::failure(MillePedeError::SteeringNotFound);
0115 }
0116 mpArgs.push_back(steerPath);
0117 }
0118
0119 ACTS_INFO(" Calling pede, this may take a while depending on problem size");
0120
0121 detail::MpSolverStatus pedeProcessStatus = detail::runSolverProcess(
0122 "pede", mpArgs, workDir, logger(), cfg.redirectStdout);
0123
0124 if (pedeProcessStatus == detail::MpSolverStatus::ProgNotFound) {
0125 ACTS_ERROR("Pede executable could not be found, aborting!");
0126 return Acts::Result<Result>::failure(MillePedeError::InstallationNotFound);
0127 }
0128 if (pedeProcessStatus == detail::MpSolverStatus::FailedWorkDir) {
0129 ACTS_ERROR("Could not navigate to the run directory `" << workDir
0130 << "`, aborting!");
0131 return Acts::Result<Result>::failure(MillePedeError::SolverCrash);
0132 } else if (pedeProcessStatus != detail::MpSolverStatus::OK) {
0133 ACTS_ERROR("Pede invocation failed. Did not run alignment.");
0134 return Acts::Result<Result>::failure(MillePedeError::SolverCrash);
0135 }
0136
0137
0138
0139
0140
0141 std::filesystem::path mpExit =
0142 workDir / std::filesystem::path("millepede.end");
0143 if (!std::filesystem::exists(mpExit)) {
0144 ACTS_ERROR(
0145 "Failed to find the Pede exit code file. The alignment has likely "
0146 "failed.");
0147 return Acts::Result<Result>::failure(MillePedeError::SolverCrash);
0148 }
0149
0150
0151 auto [exitCode, exitStatus, exitMessage] = readDetailedExit(mpExit);
0152
0153
0154
0155 if (exitStatus == ExitStatus::Aborted) {
0156 ACTS_ERROR("Pede Aborted due to errors:\n "
0157 << exitMessage << "\n"
0158 << "Please check the millepede log files in " << workDir
0159 << " for more information.");
0160 return Acts::Result<Result>::failure(MillePedeError::InvalidSolution);
0161 }
0162
0163 else if (exitStatus == ExitStatus::NoSolution) {
0164 ACTS_WARNING("Pede did not find a solution:\n "
0165 << exitMessage << "\n"
0166 << "Please check the millepede log files in " << workDir
0167 << " for more information.");
0168 }
0169
0170 else if (exitStatus == ExitStatus::SeriousWarnings) {
0171 ACTS_WARNING("Pede exited with severe warnings:\n "
0172 << exitMessage << "\n"
0173 << "You should check the millepede log files in " << workDir
0174 << " for more information.");
0175 }
0176
0177 else if (exitStatus == ExitStatus::TolerableWarnings) {
0178 ACTS_INFO("Pede exited with tolerable warnings:\n "
0179 << exitMessage << "\n"
0180 << "You can check the millepede log files in " << workDir
0181 << " for more information.");
0182 } else {
0183 ACTS_INFO("Pede exited nominally:\n "
0184 << exitMessage << "\n"
0185 << "You can check the millepede log files in " << workDir
0186 << " for more information.");
0187 }
0188
0189
0190
0191 auto outputResultFile =
0192 copyIfRequested(workDir / "millepede.res", cfg.resFileName, logger());
0193 auto outputLogFile =
0194 copyIfRequested(workDir / "millepede.log", cfg.logFileName, logger());
0195 auto outputHisFile =
0196 copyIfRequested(workDir / "millepede.his", cfg.histoFileName, logger());
0197 auto outputEvFile =
0198 copyIfRequested(workDir / "millepede.eve", cfg.evFileName, logger());
0199
0200
0201
0202 if (outputResultFile.empty()) {
0203 ACTS_ERROR("Failed to find Millepede result file expected at "
0204 << workDir / "millepede.res");
0205 return Acts::Result<Result>::failure(MillePedeError::SolutionNotReadable);
0206 }
0207
0208 ACTS_INFO("=== Congratulations, the alignment finished! ===");
0209
0210 return Result{
0211 .exitCode = exitCode,
0212 .exitStatus = exitStatus,
0213 .exitMessage = exitMessage,
0214 .resultsFile = outputResultFile,
0215 .logFile = outputLogFile,
0216 .histoFile = outputHisFile,
0217 .evFile = outputEvFile
0218 };
0219 }
0220
0221 }