Skip to content

PHGarfield updates for variable electric field and CDB interface.#4321

Merged
pinkenburg merged 1 commit into
sPHENIX-Collaboration:masterfrom
tkhemmick:PHGarfield
Jun 27, 2026
Merged

PHGarfield updates for variable electric field and CDB interface.#4321
pinkenburg merged 1 commit into
sPHENIX-Collaboration:masterfrom
tkhemmick:PHGarfield

Conversation

@tkhemmick

@tkhemmick tkhemmick commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

comment: Url gas file lookup and variable E-field.> (Please tell us something about this pull request)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • [x ] New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work for users)
  • Requiring change in macros repository (Please provide links to the macros pull request in the last section)
  • I am a member of GitHub organization of sPHENIX Collaboration, EIC, or ECCE (contact Chris Pinkenburg to join)

What kind of change does this PR introduce? (Bug fix, feature, ...)

TODOs (if applicable)

Links to other PRs in macros and calibration repositories (if applicable)

AI-generated summaries can make mistakes, so please use judgment when reviewing this.

Motivation / context

  • Extend PHGarfield gas handling to support lookup tables that vary with electric field, magnetic field, and angle.
  • Switch gas-file selection to a CDB tag-based interface, while preserving a hard-coded fallback path if the CDB entry is unavailable.

Key changes

  • Reworked gas-file merging to operate on field-indexed .gas files discovered in a directory.
  • Added validation that the expected (E, B) file grid is complete before merging.
  • Updated PHGarfield to load either a single gas file or a directory of merged gas files.
  • Added CDB-based gasfile discovery with fallback to the default gas directory/path.
  • Added gas-summary reporting after initialization.
  • Cleaned up resource management by explicitly deleting Garfield-related pointers in the destructor.

Potential risk areas

  • IO format changes: gas-file naming and directory structure are now significant inputs to loading behavior.
  • Reconstruction behavior: merging logic now depends on the new field-indexed gas tables, which may affect downstream response calculation.
  • Thread-safety: new shared state around gas loading and cached configuration should be reviewed for concurrent use.
  • Performance: directory scanning and multi-stage merging may increase initialization cost.

Possible future improvements

  • Complete and validate the remaining CDB tag wiring.
  • Add stronger diagnostics for missing or partially populated gas grids.
  • Consider caching or prevalidation to reduce startup overhead.
  • Add tests covering fallback behavior, file-grid completeness, and merge ordering.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR replaces the gas-merge validation utility with a command-line merger for E###_B###.gas inputs and updates PHGarfield to load either a direct gas file or merged gas-directory output, then report the loaded field grid.

Changes

Gas merge tooling and loader updates

Layer / File(s) Summary
MergeGasFiles CLI merge pipeline
offline/packages/PHGarfield/MergeGasFiles.cc
main() scans E###_B###.gas files, verifies the (E,B) grid, merges them into MERGED_E###.gas, and writes the final output file.
PHGarfield interface and state
offline/packages/PHGarfield/PHGarfield.h, offline/packages/PHGarfield/PHGarfield.cc
The class declaration adds PrintGasSummary, changes the destructor declaration, names process_event(topNode), and adds m_defaultGasfile and m_GasFilesLoaded; the implementation sets m_defaultGasfile and deletes the owned gas pointers.
Gas path selection and loading
offline/packages/PHGarfield/PHGarfield.cc
InitRun reads PHGARFIELD_GAS, falls back to m_defaultGasfile, and InitializeGas loads a regular gas file or ordered MERGED_E###.gas files before PrintGasSummary reports the field grid.

Sequence Diagram(s)

MergeGasFiles CLI merge flow

sequenceDiagram
  participant main as main(argc, argv)
  participant scan as searchAndUnpackDirectory
  participant fs as std::filesystem
  participant gas as Garfield::MediumMagboltz
  main->>scan: validate path_to_gasfiles
  scan->>fs: iterate directory entries
  scan-->>main: Eindices, Bindices, FileList
  main->>gas: load and merge E/B files
  main->>fs: write MERGED_E###.gas and output file
Loading

PHGarfield gas loading flow

sequenceDiagram
  participant init as PHGarfield::InitRun
  participant cdb as CDB
  participant fs as std::filesystem
  participant load as PHGarfield::InitializeGas
  participant gas as Garfield::MediumMagboltz
  participant summary as PHGarfield::PrintGasSummary
  init->>cdb: read PHGARFIELD_GAS
  init->>fs: check configured path
  init->>load: pass file or directory path
  load->>gas: load a file or merge MERGED_E###.gas
  load->>summary: print the field grid
  summary->>gas: GetFieldGrid(...)
Loading

Possibly related PRs


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 65662fc1-cb67-454c-b298-51b96c860d77

📥 Commits

Reviewing files that changed from the base of the PR and between c89585e and 7f16408.

📒 Files selected for processing (3)
  • offline/packages/PHGarfield/MergeGasFiles.cc
  • offline/packages/PHGarfield/PHGarfield.cc
  • offline/packages/PHGarfield/PHGarfield.h

Comment on lines +68 to +82
if (firstB)
{
gas.LoadGasFile(nextfile);
firstB = false;
}
else
{
gas.MergeGasFile(nextfile, true);
}
}

const std::string mergedFile = mergedName(path, Eindex);

std::cout << "Writing " << mergedFile << std::endl;
gas.WriteGasFile(mergedFile);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only check: inspect local Garfield declarations/usages if available.
fd -i 'Medium.*' . --exec rg -n -C2 '\b(LoadGasFile|MergeGasFile|WriteGasFile)\s*\(' {}
rg -n -C2 '\b(LoadGasFile|MergeGasFile|WriteGasFile)\s*\(' offline/packages/PHGarfield

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 3524


🏁 Script executed:

#!/bin/bash
# Find the header file containing the Medium class or Garfield gas file interface
fd -i 'Medium*.h' . --exec rg -n -C5 '\b(LoadGasFile|MergeGasFile)\s*\(' {}
# Also try to find the class definition directly
rg -n '\bclass\s+\w+.*\{[^}]*LoadGasFile' -t h

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 172


🏁 Script executed:

#!/bin/bash
# Search for method definitions (implementation)
rg -n 'bool.*LoadGasFile|bool.*MergeGasFile' -t cc -t h -t C C++
rg -n 'auto.*LoadGasFile|auto.*MergeGasFile' -t cc -t h -t C C++
# Search for includes that might point to external Garfield headers
rg -n '`#include`.*Garfield|Garfield' offline/packages/PHGarfield --include '*.h' --include '*.cc' | head -20

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 668


🏁 Script executed:

#!/bin/bash
# Search for method definitions (implementation) using correct rg syntax
rg -n 'bool.*LoadGasFile|bool.*MergeGasFile' -t c -t cpp
rg -n 'auto.*LoadGasFile|auto.*MergeGasFile' -t c -t cpp
# Search for includes that might point to external Garfield headers
rg -n '`#include`.*Garfield' offline/packages/PHGarfield -A 2
# Check the actual class name used for the gas object in MergeGasFiles.cc
head -100 offline/packages/PHGarfield/MergeGasFiles.cc | rg -A 5 -B 5 'MergeGasFiles'

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 172


🏁 Script executed:

#!/bin/bash
# Search for method definitions using broad pattern matching
rg -n '\bLoadGasFile' offline/packages/PHGarfield -A 5 -B 5 | head -50
# Get the first 50 lines to understand the class structure
head -50 offline/packages/PHGarfield/MergeGasFiles.cc
# Search for type declarations of 'gas' variable
rg -n '^\s*(.*\s+)?gas\s+' offline/packages/PHGarfield/MergeGasFiles.cc | head -10

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 4343


Fail the merge when Garfield load/merge operations fail.

The LoadGasFile and MergeGasFile methods on Garfield::MediumMagboltz return a boolean status (as established in PHGarfield.cc:258), but MergeGasFiles.cc ignores these values. A corrupt or incompatible gas file can silently produce partial or invalid output (MERGED_E###.gas or final merged file) while the tool reports success.

  • Lines 68–76: gas.LoadGasFile(nextfile) and gas.MergeGasFile(nextfile, true) are called without checking return status.
  • Lines 109–117: Same issue occurs during the final merge loop.
  • Bonus finding: PHGarfield.cc:295 also ignores the LoadGasFile return value in its merge loop.

Apply the check used in PHGarfield.cc:258 to all calls in this file:

-      gas.LoadGasFile(nextfile);
+      if (!gas.LoadGasFile(nextfile))
+        {
+          std::cerr << PHWHERE << " Failed to load " << nextfile << std::endl;
+          return 1;
+        }
-      gas.MergeGasFile(nextfile, true);
+      if (!gas.MergeGasFile(nextfile, true))
+        {
+          std::cerr << PHWHERE << " Failed to merge " << nextfile << std::endl;
+          return 1;
+        }

This ensures data integrity by preventing silent corruption of output files.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (firstB)
{
gas.LoadGasFile(nextfile);
firstB = false;
}
else
{
gas.MergeGasFile(nextfile, true);
}
}
const std::string mergedFile = mergedName(path, Eindex);
std::cout << "Writing " << mergedFile << std::endl;
gas.WriteGasFile(mergedFile);
if (firstB)
{
if (!gas.LoadGasFile(nextfile))
{
std::cerr << PHWHERE << " Failed to load " << nextfile << std::endl;
return 1;
}
firstB = false;
}
else
{
if (!gas.MergeGasFile(nextfile, true))
{
std::cerr << PHWHERE << " Failed to merge " << nextfile << std::endl;
return 1;
}
}
}
const std::string mergedFile = mergedName(path, Eindex);
std::cout << "Writing " << mergedFile << std::endl;
gas.WriteGasFile(mergedFile);

Comment on lines +70 to +79

// Here we fetch the gas from the CDB
std::string gasfile = m_cdb->getUrl("PHGARFIELD_GAS");
if (gasfile.empty() || !fs::exists(gasfile))
{
std::cerr << PHWHERE << " Missing CDB gasfile: " << gasfile << std::endl;
std::cerr << PHWHERE << " Using default gasfile: " << m_defaultGasfile << std::endl;
gasfile = m_defaultGasfile;
}
InitializeGas(gasfile);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only verification of Garfield and Fun4All APIs.
rg -n -C3 '\bMergeGasFile\s*\(' .
rg -n -C3 '\bABORTRUN\b|\bABORTEVENT\b|\bDISCARDEVENT\b' offline/framework offline/packages | head -80

Repository: sPHENIX-Collaboration/coresoftware

Length of output: 6425


🌐 Web query:

Garfield++ MediumMagboltz MergeGasFile return type signature

💡 Result:

The return type signature for the MergeGasFile method in the Garfield++ MediumMagboltz class (inherited from MediumGas) is bool [1][2]. The full method signature is: bool MergeGasFile(const std::string &filename, const bool replaceOld) [1][3] This method is used to read a table of gas properties from a specified file and merge it with the existing dataset [1][4]. The replaceOld parameter is a boolean flag indicating whether to replace existing data if conflicts occur [4].

Citations:


🌐 Web query:

Garfield++ MediumMagboltz LoadGasFile return type signature

💡 Result:

In Garfield++, the LoadGasFile method, which is inherited by the MediumMagboltz class from the base class MediumGas [1][2], has the following function signature: bool LoadGasFile(const std::string& filename, const bool quiet = false); This method reads a table of gas properties (transport parameters) from a specified file [1][2]. It returns a boolean value, where true typically indicates success and false indicates an error occurred during the loading process [1][2][3]. The second parameter, quiet, is optional and defaults to false; setting it to true suppresses output messages [2][4].

Citations:


Make gas initialization fail closed instead of continuing with an unloaded gas.

InitializeGas currently returns void and only logs errors, allowing InitRun to proceed with a potentially invalid Garfield::MediumMagboltz object if the gas file or directory loading fails. Garfield++'s LoadGasFile and MergeGasFile both return bool to indicate success. Ignoring these return values risks downstream segmentation faults or incorrect physics results when the gas object is in an uninitialized state.

Adopt a fail-closed pattern by returning Fun4AllReturnCodes::ABORTRUN on any gas initialization failure:

  1. Change InitializeGas return type to bool and propagate failures from LoadGasFile and MergeGasFile.
  2. Return ABORTRUN in InitRun if InitializeGas returns false.
  3. Verify directory scans yield at least one file before attempting loads.
Suggested changes

PHGarfield.h

-  void InitializeGas(const std::string &name);
+  bool InitializeGas(const std::string &name);

PHGarfield.cc

-  InitializeGas(gasfile);
+  if (!InitializeGas(gasfile))
+    {
+      return Fun4AllReturnCodes::ABORTRUN;
+    }
-void PHGarfield::InitializeGas(const std::string &name)
+bool PHGarfield::InitializeGas(const std::string &name)
 {
+  m_GasFilesLoaded = false;
   //  Create and fill the gas object so that we can trace particles through the gas...
   m_gas = new Garfield::MediumMagboltz();

   if (!std::filesystem::exists(name))
   {
     std::cerr << "Missing gas file or gas directory: " << name << std::endl;
-    return;
+    return false;
   }
 ...
       if (!m_gas->LoadGasFile(name))
-	{
-	  std::cerr << "Failed to load " << name << std::endl;
-	  return;
-	}
+	{
+	  std::cerr << "Failed to load " << name << std::endl;
+	  return false;
+	}
       m_GasFilesLoaded = true;
 ...
       if (FilesToMerge.empty())
-	{
-	  std::cerr << PHWHERE << " No MERGED_E###.gas files found in " << name << std::endl;
-	}
+	{
+	  std::cerr << PHWHERE << " No MERGED_E###.gas files found in " << name << std::endl;
+	  return false;
+	}
       bool firstE = true;
       for (const auto& [key, filepath] : FilesToMerge)
 	{
 	  if (firstE)
 	    {
-	      m_gas->LoadGasFile(filepath);
+	      if (!m_gas->LoadGasFile(filepath)) { return false; }
 	      firstE = false;
 	      m_GasFilesLoaded = true;
 	    }
 	  else
 	    {
-	      m_gas->MergeGasFile(filepath, true);
+	      if (!m_gas->MergeGasFile(filepath, true)) { return false; }
 	      m_GasFilesLoaded = true;
 	    }
 	}
     }

   PrintGasSummary();
+  return true;
 }

@sphenix-jenkins-ci

Copy link
Copy Markdown

Build & test report

Report for commit 7f164080b94e5c7cb905963b2aeafedd4e8f8247:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@pinkenburg pinkenburg merged commit 682d834 into sPHENIX-Collaboration:master Jun 27, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants