Guide for Particle Flow Algorithm developers in org.lcsim

This page documents the framework for developing PFA algorithms, explains the conventions used, and gives example implementations.

Conventions

In order to make the PFA components as interchangeable as possible, we have adopted some conventions. These were discussed at the January 2005 Boulder simulation workshop. They will probably evolve slowly over time.

Worked examples

Here are some example code snippets showing how to combine drivers to produce a PFA. These are written to be read by people rather than compilers, so they may need extra tweaks to run in practice. If you know of other patterns, or if you see that these examples have become out of date, please update them.

A very trivial PFA

See TrivialPFA.java in CVS for a worked implementation. Some other drivers in the same directory are referenced in the code.

public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {
    // Set up a hitmap to hold the raw calorimeter hits in the event
    // This driver reads in a bunch of List<CalorimeterHit> and writes
    // out a hitmap (a Map<Long,CalorimeterHit>) to the event.
    HitMapDriver rawHitMap = new HitMapDriver();
    rawHitMap.addInputList("EcalBarrHits");
    rawHitMap.addInputList("EcalEndcapHits");
    rawHitMap.addInputList("HcalBarrHits");
    rawHitMap.addInputList("HcalEndcapHits");
    rawHitMap.setOutput("raw hitmap");
    add(rawHitMap);

    // Set up a list of final-state Monte Carlo particles
    // This driver will write out a List<MCParticle> to the event.
    CreateFinalStateMCParticleList mcListMaker = new CreateFinalStateMCParticleList("Gen");
    add(mcListMaker);

    // Cluster the hits (perfect pattern recognition)
    // This driver will reads in the hitmap and the list of MCParticles.
    // It writes out a modified hitmap and a List<Cluster>.
    PerfectClusterer clusterer = new PerfectClusterer();
    clusterer.setInputHitMap("raw hitmap");
    clusterer.setOutputHitMap("leftover hits");
    clusterer.setOutputClusterList("perfect clusters");
    clusterer.setMCParticleList("GenFinalStateParticles");
    add(clusterer);

    // [The rest of the PFA would go here]
  }
}

Using DigiSim

Thanks to Guilherme, we have a digitisation simulation package called DigiSim which is available under org.lcsim.digisim. There is an example driver at org.lcsim.plugin.web.examples.DigiSimExample. Borrowing heavily from that, here is an example snippet showing how to use the output from DigiSim:

public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {
    // CalHitMapDriver is a driver that produces hitmaps in the format
    // needed by DigiSim:
    add(new org.lcsim.recon.cluster.util.CalHitMapDriver());
    // Run DigiSim, producing raw hit collections:
    org.lcsim.digisim.DigiSimDriver digi = new org.lcsim.digisim.DigiSimDriver();
    add(digi);
    // Convert the output to SimCalorimeterHit format for use in analysis:
    add( new org.lcsim.digisim.SimCalorimeterHitsDriver() );

    // Now we can add some more drivers to analyze the output. For example:

    // Set up a hitmap for the digisim output hits
    HitMapDriver digiHitMap = new HitMapDriver();
    digiHitMap.addInputList("EcalBarrDigiHits");
    digiHitMap.addInputList("EcalEndcapDigiHits");
    digiHitMap.addInputList("HcalBarrDigiHits");
    digiHitMap.addInputList("HcalEndcapDigiHits");
    digiHitMap.setOutput("digi hitmap");
    add(digiHitMap);

    // Set up the MC list
    CreateFinalStateMCParticleList mcListMaker = new CreateFinalStateMCParticleList("Gen");
    add(mcListMaker);

    // Cluster the hits (perfect pattern recognition)
    PerfectClusterer clusterer = new PerfectClusterer();
    clusterer.setInputHitMap("digi hitmap");
    clusterer.setOutputHitMap("leftover hits");
    clusterer.setOutputClusterList("perfect clusters");
    clusterer.setMCParticleList("GenFinalStateParticles");
    add(clusterer);
  }
}

Reading in and writing out hitmaps

If you are writing your own drivers to use in a PFA, you will probably need to read in hitmaps, and maybe also write out a modified hitmap. Here is a snippet showing how to do this.

public class HitMapReader extends Driver
{
  public HitMapReader(String inputName, String outputName)
  {
    m_inputName = inputName;
    m_outputName = outputName;
  }

  public void process(EventHeader event)
  {
    // Read in the hitmap with the given name from the event.
    Map<Long, CalorimeterHit> inputHitMap = (Map<Long, CalorimeterHit>) (event.get(m_name));
    // Now produce a clone so we can write it out later:
    Map<Long, CalorimeterHit> outputHitMap = new HashMap<Long, CalorimeterHit>(inputHitMap); // initially cloned

    // [Do some manipulation here, e.g. making clusters and removing their hits from outputHitMap]

    // Example: Here's one way to loop over the hits in the hitmap:
    for (CalorimeterHit hit : inputHitMap.values()) {
      System.out.println("Here is a hit: "+hit);
    }

    // Write out the hitmap:
    event.put(m_outputHitMapName, outputHitMap);
  }

  String m_inputName;
  String m_outputName;
}

How to make things appear in WIRED or the Event Browser in JAS3

One nice feature of JAS3 is that when you open a file in org.lcsim mode, you can upload stuff to the event and have it appear in the org.lcsim Event Browser and the WIRED display (see: Displaying analysis objects with wired). But there are a few tricks to make this work:

Here is a code snippet that allows you to display hitmaps:

// Here is the PFA class:
public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {
    // [drivers go here, producing a hitmap called "digi hitmap"]

    // Here's the driver to convert the hitmap into something WIRED can display:
    HitMapConverter digiConverterDriver = new HitMapConverter();
    digiConverterDriver.setInputHitMap("digi hitmap");
    digiConverterDriver.setOutputList("digi hits (displayable)");
    add(digiConverterDriver);

    // [rest of the code goes here]
  }
}

// Here is the converter class:
public class HitMapConverter extends Driver
{
  // Constructor, setup methods:
  public HitMapConverter() {}
  public void setInputHitMap(String name) {m_inputHitMapName = name;}
  public void setOutputList(String name) {m_outputListName = name;}

  // Do the conversion:
  public void process(EventHeader event) 
  {
    Map<Long, CalorimeterHit> inputHitMap = (Map<Long, CalorimeterHit>) (event.get(m_inputHitMapName));
    List<Cluster> outputClusterList = new Vector<Cluster>();
    for (CalorimeterHit hit : inputHitMap.values()) {
      BasicCluster clus = new BasicCluster();
      clus.addHit(hit);
      outputClusterList.add(clus);
    }
    event.put(m_outputListName, outputClusterList);
  }

  String m_inputHitMapName;
  String m_outputListName;
}

Things that need doing

Updates needed in the code:

Updates needed on this page: