13 #ifndef DD4HEP_DDCORE_PANDORACONVERTER_H
14 #define DD4HEP_DDCORE_PANDORACONVERTER_H
99 : doc(0), doc_root(0), doc_calorimeters(0), doc_detector(0), doc_coil(0), doc_tracking(0) {
116 const char empty_xml[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\">\n"
118 " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
119 " ++++ Linear collider detector description in C++ ++++\n"
120 " ++++ dd4hep Detector description generator. ++++\n"
122 " ++++ M.Frank CERN/LHCb ++++\n"
123 " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
125 "<pandoraSetup>\n\0\0";
131 geo.
doc = docH.
parse(empty_xml,
sizeof(empty_xml));
145 static long create_description(
Detector& ,
int ,
char** ) {
146 throw runtime_error(
"The pandora xml conversion plugin is not yet implemented");
150 package org.lcsim.geometry.compact.converter.pandora;
152 import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_BARREL;
153 import static org.lcsim.geometry.Calorimeter.CalorimeterType.EM_ENDCAP;
154 import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_BARREL;
155 import static org.lcsim.geometry.Calorimeter.CalorimeterType.HAD_ENDCAP;
156 import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_BARREL;
157 import static org.lcsim.geometry.Calorimeter.CalorimeterType.MUON_ENDCAP;
158 import hep.physics.particle.properties.ParticlePropertyManager;
159 import hep.physics.particle.properties.ParticleType;
160 import hep.physics.vec.BasicHep3Vector;
161 import hep.physics.vec.Hep3Vector;
163 import java.io.InputStream;
164 import java.io.OutputStream;
165 import java.text.DecimalFormat;
166 import java.util.ArrayList;
167 import java.util.List;
168 import java.util.StringTokenizer;
170 import javax.swing.filechooser.FileFilter;
172 import org.jdom.Document;
173 import org.jdom.Element;
174 import org.jdom.output.Format;
175 import org.jdom.output.XMLOutputter;
176 import org.lcsim.conditions.ConditionsManager;
177 import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
178 import org.lcsim.conditions.ConditionsSet;
179 import org.lcsim.detector.material.BetheBlochCalculator;
180 import org.lcsim.detector.material.IMaterial;
181 import org.lcsim.detector.material.MaterialStore;
182 import org.lcsim.detector.solids.Tube;
183 import org.lcsim.geometry.Calorimeter;
184 import org.lcsim.geometry.Calorimeter.CalorimeterType;
185 import org.lcsim.geometry.Detector;
186 import org.lcsim.geometry.GeometryReader;
187 import org.lcsim.geometry.compact.Subdetector;
188 import org.lcsim.geometry.compact.converter.Converter;
189 import org.lcsim.geometry.field.Solenoid;
190 import org.lcsim.geometry.layer.Layer;
191 import org.lcsim.geometry.layer.LayerSlice;
192 import org.lcsim.geometry.layer.LayerStack;
193 import org.lcsim.geometry.segmentation.AbstractCartesianGrid;
194 import org.lcsim.geometry.subdetector.AbstractPolyhedraCalorimeter;
195 import org.lcsim.geometry.subdetector.MultiLayerTracker;
196 import org.lcsim.geometry.util.BaseIDDecoder;
197 import org.lcsim.geometry.util.IDDescriptor;
198 import org.lcsim.geometry.util.SamplingFractionManager;
207 public class Main
implements Converter
209 private final static boolean DEBUG =
false;
212 private ConditionsManager conditionsManager = ConditionsManager.defaultInstance();
215 static final DecimalFormat xlen =
new DecimalFormat(
"#.########");
216 static final DecimalFormat xfrac =
new DecimalFormat(
"#.########");
217 static final DecimalFormat xthick =
new DecimalFormat(
"#.######");
224 static class SamplingLayerRange
231 SamplingLayerRange(
int lowerLayer,
int upperLayer,
double em,
double had)
233 this.lowerLayer = lowerLayer;
234 this.upperLayer = upperLayer;
239 public boolean inRange(
int layerNumber)
241 return layerNumber >= lowerLayer && layerNumber <= upperLayer;
244 public int getLowerLayer()
249 public int getUpperLayer()
254 public double getEMSampling()
259 public double getHADSampling()
272 static class SamplingLayers
extends ArrayList<SamplingLayerRange>
274 public SamplingLayers()
278 public SamplingLayers(SamplingLayerRange range)
283 public SamplingLayers(List<SamplingLayerRange> ranges)
288 public SamplingLayerRange getSamplingLayerRange(
int layern)
290 for (SamplingLayerRange range :
this)
292 if (range.inRange(layern))
304 private static class CalorimeterConditions
306 SamplingLayers samplingLayers;
315 StringBuffer buff =
new StringBuffer();
316 buff.append(name +
'\n');
317 for (SamplingLayerRange range : samplingLayers)
319 buff.append(
"[" + range.getLowerLayer() +
" - " + range.getUpperLayer() +
"]" +
'\n');
320 buff.append(
" em = " + range.getEMSampling() +
'\n');
321 buff.append(
" had = " + range.getHADSampling() +
'\n');
324 return buff.toString();
327 public SamplingLayers getSamplingLayers()
329 return samplingLayers;
339 protected CalorimeterConditions(Calorimeter calorimeter, ConditionsSet conditions)
342 this.name = calorimeter.getName();
346 String layeringName =
null;
347 if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
349 layeringName =
"ECalLayering";
351 else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
353 layeringName =
"HCalLayering";
355 else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
357 layeringName =
"MuonLayering";
361 throw new RuntimeException(
"Don't know how to handle CalorimeterConditions for " + calorimeter.getName() +
".");
364 String emName =
null;
365 String hadName =
null;
366 if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL)
368 emName =
"EMBarrel_SF";
369 hadName =
"HadBarrel_SF";
371 else if (calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
373 emName =
"EMEndcap_SF";
374 hadName =
"HadEndcap_SF";
377 if (emName ==
null || hadName ==
null)
379 throw new RuntimeException(
"Sampling fractions not found for " + calorimeter.getName() +
".");
382 String emSampling = conditions.getString(emName);
383 String hadSampling = conditions.getString(hadName);
384 List<Double> emSamplingFractions =
new ArrayList<Double>();
385 List<Double> hadSamplingFractions =
new ArrayList<Double>();
386 StringTokenizer tok =
new StringTokenizer(emSampling,
",");
387 while (tok.hasMoreTokens())
389 Double emSamplingFraction = Double.valueOf(tok.nextToken().trim());
390 emSamplingFractions.add(emSamplingFraction);
392 tok =
new StringTokenizer(hadSampling,
",");
393 while (tok.hasMoreTokens())
395 Double hadSamplingFraction = Double.valueOf(tok.nextToken().trim());
396 hadSamplingFractions.add(hadSamplingFraction);
399 String layering = conditions.getString(layeringName);
400 tok =
new StringTokenizer(layering,
",");
401 List<Integer> layers =
new ArrayList<Integer>();
402 int maxLayer = calorimeter.getLayering().getLayerCount() - 1;
403 while (tok.hasMoreTokens())
405 String nextToken = tok.nextToken().trim();
406 int nextLayer = Integer.valueOf(nextToken);
407 layers.add(nextLayer);
412 int samplingIndex = 0;
413 if (calorimeter.getCalorimeterType() == HAD_BARREL || calorimeter.getCalorimeterType() == HAD_ENDCAP)
415 samplingIndex = (
new StringTokenizer(conditions.getString(
"ECalLayering"),
",").countTokens());
417 if (calorimeter.getCalorimeterType() == MUON_BARREL || calorimeter.getCalorimeterType() == MUON_ENDCAP)
419 samplingIndex = (
new StringTokenizer(conditions.getString(
"ECalLayering"),
",").countTokens());
420 samplingIndex += (
new StringTokenizer(conditions.getString(
"HCalLayering"),
",").countTokens());
426 samplingLayers =
new SamplingLayers();
427 for (
int i = 0; i < layers.size(); i++)
430 int lowerLayer = layers.get(i);
432 if (i + 1 > layers.size() - 1)
433 upperLayer = maxLayer;
435 upperLayer = layers.get(i + 1) - 1;
438 double emSamplingFraction = emSamplingFractions.get(samplingIndex);
439 double hadSamplingFraction = hadSamplingFractions.get(samplingIndex);
440 SamplingLayerRange samplingLayerRange =
new SamplingLayerRange(lowerLayer, upperLayer, emSamplingFraction, hadSamplingFraction);
444 samplingLayers.add(samplingLayerRange);
450 String mipCondition =
null;
451 String mipSigmaCondition =
null;
452 String mipCutCondition =
null;
455 if (calorimeter.getCalorimeterType() == CalorimeterType.EM_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.EM_ENDCAP)
457 mipCondition =
"ECalMip_MPV";
458 mipSigmaCondition =
"ECalMip_sig";
459 mipCutCondition =
"ECalMip_Cut";
461 else if (calorimeter.getCalorimeterType() == CalorimeterType.HAD_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.HAD_ENDCAP)
463 mipCondition =
"HCalMip_MPV";
464 mipSigmaCondition =
"HCalMip_sig";
465 mipCutCondition =
"HCalMip_Cut";
467 else if (calorimeter.getCalorimeterType() == CalorimeterType.MUON_BARREL || calorimeter.getCalorimeterType() == CalorimeterType.MUON_ENDCAP)
469 mipCondition =
"MuonMip_MPV";
470 mipSigmaCondition =
"MuonMip_sig";
471 mipCutCondition =
"MuonMip_Cut";
473 mipEnergy = conditions.getDouble(mipCondition);
474 mipSigma = conditions.getDouble(mipSigmaCondition);
475 mipCut = conditions.getDouble(mipCutCondition);
476 timeCut = conditions.getDouble(
"timeCut");
486 public SamplingLayerRange getSamplingLayerRange(
int layer)
488 for (SamplingLayerRange layers : this.samplingLayers)
490 if (layers.inRange(layer))
496 public double getMipEnergy()
501 public double getMipSigma()
506 public double getMipCut()
511 public double getTimeCut()
517 public void convert(String inputFileName, InputStream in, OutputStream out)
throws Exception
519 GeometryReader reader =
new GeometryReader();
521 String detectorName =
det.getDetectorName();
524 conditionsManager.setDetector(detectorName, 0);
526 catch (ConditionsNotFoundException x)
528 throw new RuntimeException(
"Failed to setup conditions system for detector: " + detectorName, x);
530 Document doc = convertDetectorToPandora(
det);
531 XMLOutputter outputter =
new XMLOutputter();
534 outputter.setFormat(Format.getPrettyFormat());
535 outputter.output(doc, out);
540 public Document convertDetectorToPandora(
Detector detector)
543 Document outputDoc =
new Document();
544 Element root =
new Element(
"pandoraSetup");
545 outputDoc.setRootElement(root);
546 Element calorimeters =
new Element(
"calorimeters");
547 root.addContent(calorimeters);
550 Element detectorTag =
new Element(
"detector");
551 detectorTag.setAttribute(
"name", detector.getDetectorName());
552 root.addContent(detectorTag);
555 ConditionsSet calorimeterCalibration =
null;
558 calorimeterCalibration = conditionsManager.getConditions(
"CalorimeterCalibration");
563 boolean haveCalCalib = (calorimeterCalibration ==
null) ?
false :
true;
566 for (Subdetector subdetector : detector.getSubdetectors().values())
570 if (subdetector instanceof AbstractPolyhedraCalorimeter)
572 Element calorimeter =
new Element(
"calorimeter");
573 AbstractPolyhedraCalorimeter polycal = (AbstractPolyhedraCalorimeter) subdetector;
577 Calorimeter.CalorimeterType calType = polycal.getCalorimeterType();
578 if (calType.equals(HAD_BARREL) || calType.equals(HAD_ENDCAP) || calType.equals(EM_ENDCAP) || calType.equals(EM_BARREL) || calType.equals(MUON_BARREL) || calType.equals(MUON_ENDCAP))
581 calorimeter.setAttribute(
"type", Calorimeter.CalorimeterType.toString(calType));
582 calorimeter.setAttribute(
"innerR", Double.toString(polycal.getInnerRadius()));
583 calorimeter.setAttribute(
"innerZ", Double.toString(polycal.getInnerZ()));
584 calorimeter.setAttribute(
"innerPhi", Double.toString(polycal.getSectionPhi()));
585 calorimeter.setAttribute(
"innerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
586 calorimeter.setAttribute(
"outerR", Double.toString(polycal.getOuterRadius()));
587 calorimeter.setAttribute(
"outerZ", Double.toString(polycal.getOuterZ()));
588 calorimeter.setAttribute(
"outerPhi", Double.toString(polycal.getSectionPhi()));
589 calorimeter.setAttribute(
"outerSymmetryOrder", Double.toString(polycal.getNumberOfSides()));
590 calorimeter.setAttribute(
"collection", subdetector.getReadout().getName());
593 List<Double> cellSizes = getCellSizes(subdetector);
596 if (subdetector.isEndcap())
598 calorimeter.setAttribute(
"cellSizeU", Double.toString(cellSizes.get(0)));
599 calorimeter.setAttribute(
"cellSizeV", Double.toString(cellSizes.get(1)));
602 else if (subdetector.isBarrel())
604 calorimeter.setAttribute(
"cellSizeU", Double.toString(cellSizes.get(1)));
605 calorimeter.setAttribute(
"cellSizeV", Double.toString(cellSizes.get(0)));
609 calorimeter.addContent(makeIdentifierDescription(polycal));
612 calorimeters.addContent(calorimeter);
614 LayerStack layers = polycal.getLayering().getLayerStack();
616 Element layersElem =
new Element(
"layers");
617 layersElem.setAttribute(
"nlayers", Integer.toString(layers.getNumberOfLayers()));
619 calorimeter.addContent(layersElem);
623 if (polycal.isBarrel())
625 layerD = polycal.getInnerRadius();
627 else if (polycal.isEndcap())
629 layerD = polycal.getInnerZ();
632 CalorimeterConditions subdetectorCalorimeterConditions =
null;
636 subdetectorCalorimeterConditions =
new CalorimeterConditions((Calorimeter) subdetector, calorimeterCalibration);
642 calorimeter.setAttribute(
"mipEnergy", xfrac.format(subdetectorCalorimeterConditions.getMipEnergy()));
643 calorimeter.setAttribute(
"mipSigma", xfrac.format(subdetectorCalorimeterConditions.getMipSigma()));
644 calorimeter.setAttribute(
"mipCut", xfrac.format(subdetectorCalorimeterConditions.getMipCut()));
645 calorimeter.setAttribute(
"timeCut", xfrac.format(subdetectorCalorimeterConditions.getTimeCut()));
651 List<LayerSlice> sensors = subdetector.getLayering().getLayerStack().getLayer(0).getSensors();
653 IMaterial sensorMaterial = MaterialStore.getInstance().get(sensor.getMaterial().getName());
655 ParticleType particleType = ParticlePropertyManager.getParticlePropertyProvider().get(13);
657 Hep3Vector p =
new BasicHep3Vector(-6.8641, -7.2721, 1.2168e-7);
659 double emip = BetheBlochCalculator.computeBetheBloch(sensorMaterial, p, particleType.getMass(), particleType.getCharge(), sensor.getThickness());
662 calorimeter.setAttribute(
"mipEnergy", xfrac.format(emip));
665 calorimeter.setAttribute(
"mipSigma",
"0");
666 calorimeter.setAttribute(
"mipCut",
"0");
667 calorimeter.setAttribute(
"timeCut", xfrac.format(Double.MAX_VALUE));
672 for (
int i = 0; i < layers.getNumberOfLayers(); i++)
675 Layer layer = layers.getLayer(i);
677 Element layerElem =
new Element(
"layer");
678 layersElem.addContent(layerElem);
683 for (
int j = 0; j < layer.getNumberOfSlices(); j++)
687 double x0 = slice.getMaterial().getRadiationLength();
690 radLen += slice.getThickness() / (x0*10);
693 double lambda = slice.getMaterial().getNuclearInteractionLength();
694 intLen += slice.getThickness() / (lambda*10);
702 layerElem.setAttribute(
"radLen", xlen.format(radLen));
703 layerElem.setAttribute(
"intLen", xlen.format(intLen));
706 double layerD2 = layerD + layer.getThicknessToSensitiveMid();
707 layerElem.setAttribute(
"distanceToIp", xthick.format(layerD2));
710 layerElem.setAttribute(
"cellThickness", xthick.format(layer.getThickness()));
716 SamplingLayerRange layerRange = subdetectorCalorimeterConditions.getSamplingLayerRange(i);
717 if (calType == EM_BARREL || calType == EM_ENDCAP)
719 layerElem.setAttribute(
"samplingFraction", xfrac.format(layerRange.getEMSampling()));
721 if (calType == HAD_BARREL || calType == HAD_ENDCAP)
723 layerElem.setAttribute(
"samplingFraction", xfrac.format(layerRange.getHADSampling()));
725 if (calType == MUON_BARREL || calType == MUON_ENDCAP)
727 layerElem.setAttribute(
"samplingFraction", xfrac.format(layerRange.getHADSampling()));
729 layerElem.setAttribute(
"emSamplingFraction", xfrac.format(layerRange.getEMSampling()));
730 layerElem.setAttribute(
"hadSamplingFraction", xfrac.format(layerRange.getHADSampling()));
737 double samplingFraction = SamplingFractionManager.defaultInstance().getSamplingFraction(subdetector, i);
738 layerElem.setAttribute(
"emSamplingFraction", xfrac.format(samplingFraction));
739 layerElem.setAttribute(
"hadSamplingFraction", xfrac.format(samplingFraction));
743 layerD += layer.getThickness();
753 ConditionsSet conditions = conditionsManager.getConditions(
"SamplingFractions/" + subdetector.getName());
754 boolean isDigital = conditions.getBoolean(
"digital");
755 calorimeter.setAttribute(
"digital", String.valueOf(isDigital));
759 calorimeter.setAttribute(
"digital",
"false");
765 double coilRadLen = 0;
766 double coilIntLen = 0;
768 double coilInnerR = 0;
769 double coilOuterR = 0;
774 MultiLayerTracker c = (MultiLayerTracker) detector.getSubdetector(
"SolenoidCoilBarrel");
777 coilLayers = c.getNumberOfLayers();
778 coilInnerR = c.getInnerR()[0];
779 coilOuterR = c.getInnerR()[coilLayers-1] + c.getLayerThickness(coilLayers-1);
780 for (
int layern = 0; layern != c.getNumberOfLayers(); layern++)
782 for (
LayerSlice slice : c.getLayer(layern).getSlices())
784 double x0 = slice.getMaterial().getRadiationLength();
785 double sliceRadLen = slice.getThickness() / (x0*10);
786 double lambda = slice.getMaterial().getNuclearInteractionLength();
787 double sliceIntLen = slice.getThickness() / (lambda*10);
789 coilRadLen += sliceRadLen;
790 coilIntLen += sliceIntLen;
794 coilRadLen = coilRadLen/(coilOuterR-coilInnerR);
795 coilIntLen = coilIntLen/(coilOuterR-coilInnerR);
798 catch (ClassCastException e)
800 throw new RuntimeException(e);
804 Solenoid s = (Solenoid) detector.getFields().get(
"GlobalSolenoid");
807 bfield = s.getField(
new BasicHep3Vector(0, 0, 0)).z();
808 coilMaxZ = s.getZMax();
811 catch (ClassCastException e)
813 throw new RuntimeException(e);
816 Element coil =
new Element(
"coil");
817 coil.setAttribute(
"radLen", xlen.format(coilRadLen));
818 coil.setAttribute(
"intLen", xlen.format(coilIntLen));
819 coil.setAttribute(
"innerR", Double.toString(coilInnerR));
820 coil.setAttribute(
"outerR", Double.toString(coilOuterR));
821 coil.setAttribute(
"z", Double.toString(coilMaxZ));
822 coil.setAttribute(
"bfield", Double.toString(bfield));
823 root.addContent(coil);
825 Tube tube = (
Tube) detector.getTrackingVolume().getLogicalVolume().getSolid();
826 Element tracking =
new Element(
"tracking");
827 tracking.setAttribute(
"innerR", Double.toString(tube.getInnerRadius()));
828 tracking.setAttribute(
"outerR", Double.toString(tube.getOuterRadius()));
829 tracking.setAttribute(
"z", Double.toString(tube.getZHalfLength()));
830 root.addContent(tracking);
835 Element makeIdentifierDescription(Subdetector subdet)
837 IDDescriptor descr = subdet.getIDDecoder().getIDDescription();
838 Element
id =
new Element(
"id");
839 for (
int i = 0, j = descr.fieldCount(); i < j; i++)
841 Element field =
new Element(
"field");
842 field.setAttribute(
"name", descr.fieldName(i));
843 field.setAttribute(
"length", Integer.toString(descr.fieldLength(i)));
844 field.setAttribute(
"start", Integer.toString(descr.fieldStart(i)));
845 field.setAttribute(
"signed", Boolean.toString(descr.isSigned(i)));
847 id.addContent(field);
852 private List<Double> getCellSizes(Subdetector subdetector)
854 List<Double> cellSizes =
new ArrayList<Double>();
855 BaseIDDecoder dec = (BaseIDDecoder) subdetector.getReadout().getIDDecoder();
856 if (dec instanceof AbstractCartesianGrid)
858 AbstractCartesianGrid cgrid = (AbstractCartesianGrid) dec;
859 if (cgrid.getGridSizeX() != 0)
861 cellSizes.add(cgrid.getGridSizeX());
863 if (cgrid.getGridSizeY() != 0)
865 cellSizes.add(cgrid.getGridSizeY());
867 if (cgrid.getGridSizeZ() != 0)
869 cellSizes.add(cgrid.getGridSizeZ());
872 if (cellSizes.size() != 2)
873 throw new RuntimeException(
"Only 2 cell dimensions are allowed.");
877 public String getOutputFormat()
882 public FileFilter getFileFilter()
884 return new PandoraFileFilter();
887 private static class PandoraFileFilter
extends FileFilter
890 public boolean accept(java.io.File file)
892 return file.getName().endsWith(
".xml");
895 public String getDescription()
897 return "Pandora Geometry file (*.xml)";