Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

...

  • PFAs should be structured as a series of Drivers. This way, components can be swapped in and out easily.
  • When PFA Drivers need to communicate with each other, they should do it by storing objects or collections of objects in the event via the put() and get() methods.
  • Groups of hits should be stored as Map<Long,CalorimeterHit> (referred to as a "hitmap") Hitmaps. The HitMap class is an extension of HashMap<Long,CalorimeterHit>. Each entry corresponds to one hit, giving the CellID and the hit itself.
  • Often, a Driver takes a hitmap HitMap as input, performs some operation on it, and produces a modified version of the hitmap HitMap as part of the output. The output hitmap HitMap should be a new, separate object (i.e. the original hitmap HitMap should be left unchanged at the end). Example code to read in and write out hitmaps is given below.
  • Clusters should be stored in the event as List<Cluster>.

...

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.

HitMap manipulation

There are several classes in the org.lcsim.util.hitmap package which can be used to manipulate HitMaps. These are generally wrapped as Drivers so that they can be dropped into a PFA template. Here is a quick list:

  • Add, subtract, or clone a named HitMap in the event via a driver:
    • HitMapAddDriver
    • HitMapSubtractDriver
    • HitMapCloneDriver
  • Convert formats (including the previous Map<Long,CalorimeterHit> format for backwards-compatability):
    • HitMapToClusterListDriver
    • HitMapToHitListDriver
    • MapToHitMapDriver
  • Filter the hits in a hitmap:
    • HitMapFilter
    • HitMapFilterDriver

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.

No Format

public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {
    // Set up a hitmap to hold the raw calorimeter hits in the event
No Format

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 upThis driver reads in a listbunch of final-stateList<CalorimeterHit> Monteand Carlo particleswrites
    // This driver will write out a List<MCParticle>HitMap to the event.
    CreateFinalStateMCParticleListHitMapDriver mcListMakerrawHitMap = new CreateFinalStateMCParticleListHitMapDriver("Gen");
    add(mcListMakerrawHitMap.addInputList("EcalBarrHits");

    // Cluster the hits (perfect pattern recognition)rawHitMap.addInputList("EcalEndcapHits");
    rawHitMap.addInputList("HcalBarrHits");
    // This driver will reads in the hitmap and the list of MCParticles.rawHitMap.addInputList("HcalEndcapHits");
    rawHitMap.setOutput("raw hitmap");
    add(rawHitMap);

    // ItSet writesup out a modified hitmap and a List<Cluster>list of final-state Monte Carlo particles
    // This driver will write out a List<MCParticle> to the event.
    PerfectClustererCreateFinalStateMCParticleList clusterermcListMaker = new PerfectClustererCreateFinalStateMCParticleList("Gen");
    clusterer.setInputHitMap("raw hitmap"add(mcListMaker);

    clusterer.setOutputHitMap("leftover hits");
    clusterer.setOutputClusterList("perfect clusters");// Cluster the hits (perfect pattern recognition)
    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:

No Format

public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {// 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);

    // CalHitMapDriver[The isrest aof driverthe thatPFA produceswould hitmapsgo inhere]
 the format
    // needed by DigiSim:
    add(new }
}

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:

No Format

public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {recon.cluster.util.CalHitMapDriver());
    // Run DigiSim, producing raw hit collections:
    org.lcsim.digisim.DigiSimDriver digi = CalHitMapDriver is a driver that produces hitmaps in the format
    // needed by DigiSim:
    add(new org.lcsim.recon.cluster.digisimutil.DigiSimDriverCalHitMapDriver();
    add(digi);
    // ConvertRun the 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 hitmapsHitMaps, and maybe also write out a modified hitmapHitMap. Here is a snippet showing how to do this.

No Format
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>HitMap inputHitMap = (Map<Long, CalorimeterHit>HitMap) (event.get(m_name));
    // Now produce a clone so we can write it out later:
    Map<Long, CalorimeterHit>HitMap outputHitMap = new HashMap<Long, CalorimeterHit>(inputHitMapHitMapinputHitMap); // 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;
}

...

  • For the Event Browser, there must be a handler class in org.lcsim.plugin.browser to tell it how to display the table. Otherwise, the thing you uploaded will appear in the list but won't display anything useful.
  • For WIRED, you also need a handler class where? or the thing you uploaded won't be visible.
  • Currently, these expect things to be uploaded as a List<Object>. So if the objects are in another format – such as a hitmap – they won't be readable.
  • There is currently a special case for CalorimeterHits. These require geometry information to interpret, and this is not supplied by default except for the initial collections (e.g. EcalBarrHits). It's possible to add this meta-information in your code, but even then a mixed collection of ECAL and HCAL hits will cause severe confusion. One work-around is to wrap all the CalorimeterHit objects into one-hit clusters. In the HEAD version of org.lcsim, the handler classes for the Wired event display and (maybe) also for the Event Browser know how do extract this for a List<CalorimeterHit>, but at the time of writing this didn't work in the most recent RELEASE package.

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

No Format


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

    // Here's is the driver to convert the hitmap into something WIRED can display: PFA class:
public class TrivialPFA extends Driver
{
  public TrivialPFA()
  {
    HitMapConverter// digiConverterDriver[drivers =go new HitMapConverter();
    digiConverterDriver.setInputHitMap(here, producing a HitMap called "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);
    }]

    // Here's the driver to convert the hitmap into a List<CalorimeterHit> to 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) 
  {
    HitMap inputHitMap = (HitMap) (event.get(m_inputHitMapName));
    List<CalorimeterHit> outputHitList = new Vector<CalorimeterHit>();
    outputHitList.addAll(inputHitMap.values());
    event.put(m_outputListName, outputClusterList);
  }

  String m_inputHitMapName;
  String m_outputListName;
}

...

Based on the discussions at Boulder, here is an outline (very abstracted!) of what a real PFA might look like. We don't yet have a full PFA implementation in this framework, though several groups are working to convert their existing code.

No Format
public class CompletePFA extends Driver
{
  public CompletePFA()
  {
    // First, use DigiSim to make more realistic hits
    add(new org.lcsim.recon.cluster.util.CalHitMapDriver());
    org.lcsim.digisim.DigiSimDriver digi = new org.lcsim.digisim.DigiSimDriver();
    add(digi);
    add( new org.lcsim.digisim.SimCalorimeterHitsDriver() );

    // Produce hitmaps:
    HitMapDriver digiHitMap = new HitMapDriver();
    digiHitMap.addInputList("EcalBarrDigiHits");
    digiHitMap.addInputList("EcalEndcapDigiHits");
    digiHitMap.addInputList("HcalBarrDigiHits");
    digiHitMap.addInputList("HcalEndcapDigiHits");
    digiHitMap.setOutput("digi hitmap");
    add(digiHitMap);

    // Find tracks with the fast MC (output is a List<Track> saved as EventHeader.TRACKS)
    add (new org.lcsim.mc.fast.tracking.MCFastTracking());

    // Run a MIP-finder, possibly taking the tracks as input.
    // "MipFinder" is a made-up class.
    MipFinder exampleMipFinder = new MipFinder();
    exampleMipFinder.setInputTrackList(EventHeader.TRACKS);
    exampleMipFinder.setInputHitMap("digi hitmap");
    exampleMipFinder.setOutputClusterList("mips");
    exampleMipFinder.setOutputHitMap("digi hitmap after removing mips");
    add(exampleMipFinder);

    // Find E/M clusters
    // "EMFinder" is a made-up class.
    EMFinder exampleEMFinder = new EMFinder();
    exampleEMFinder.setInputHitMap("digi hitmap after removing mips");
    exampleEMFinder.setOutputClusterList("em showers");
    exampleEMFinder.setOutputHitMap("digi hitmap after removing mips and em showers");
    add(exampleEMFinder);

    // Identify the E/M clusters -- photons? electrons? pi0?
    // Output is a List<ReconstructedParticle>.
    // In reality we'd probably iterate a little here on the hit assignments,
    // and might need to pick up MIP segments for a few electrons, but neglect that for now.
    // "EMIdentifier" is a made-up class.
    EMIdentifier exampleEMIdentifier = new EMIdentifier();
    exampleEMIdentifier.setInputClusterList("em showers");
    exampleEMIdentifier.setInputTrackList(EventHeader.TRACKS);
    exampleEMIdentifier.setOutputParticleList("identified em particles");

    // Now find remaining clusters, which should mostly be from hadrons (and muons)
    // after a shower/interaction/scatter. This step is very abstracted and would
    // include all kinds of things such as fragment-handling.
    // "HADClusterer" is a made-up class.
    HADClusterer exampleHADClusterer = new HADClusterer();
    exampleHADClusterer.setInputHitMap("digi hitmap after removing mips and em showers");
    exampleHADClusterer.setInputMipList("mips");
    exampleHADClusterer.setInputTrackList(EventHeader.TRACKS);
    exampleHADClusterer.setOutputHitMap("digi hitmap after removing mips, em showers, and had clusters");
    exampleHADClusterer.setOutputClusterList("had");

    // Identify the hadronic/muon particles found:
    // "HADIdentifier" is a made-up class.
    HADIdentifier exampleEMIdentifier = new EMIdentifier();
    exampleHADIdentifier.setInputClusterList("had");
    exampleHADIdentifier.setInputTrackList(EventHeader.TRACKS);
    exampleHADIdentifier.setOutputParticleList("identified had particles");

    // Then we do something useful with all these ReconstructedParticles.
    // [analysis]
  }
}

...

Updates needed in the code:

...

  • A real, live PFA in this format
  • Standard routines for telling you how well your PFA did (Ron's?)
  • Example(s) in the main org.lcsim tree, probably under org.lcsim.plugin.web.examples

...