View Javadoc

1   package org.lcsim.geometry.compact.converter.html;
2   
3   import java.text.DecimalFormat;
4   import java.text.SimpleDateFormat;
5   import java.util.ArrayList;
6   import java.util.Calendar;
7   import java.util.List;
8   import java.util.Map;
9   
10  import org.jdom.Element;
11  import org.lcsim.detector.IDetectorElement;
12  import org.lcsim.detector.tracker.silicon.SiSensor;
13  import org.lcsim.geometry.Calorimeter;
14  import org.lcsim.geometry.compact.Constant;
15  import org.lcsim.geometry.compact.Detector;
16  import org.lcsim.geometry.compact.Field;
17  import org.lcsim.geometry.compact.Header;
18  import org.lcsim.geometry.compact.Readout;
19  import org.lcsim.geometry.compact.Segmentation;
20  import org.lcsim.geometry.compact.Subdetector;
21  import org.lcsim.geometry.field.Solenoid;
22  import org.lcsim.geometry.layer.Layer;
23  import org.lcsim.geometry.layer.LayerSlice;
24  import org.lcsim.geometry.layer.LayerStack;
25  import org.lcsim.geometry.subdetector.AbstractLayeredSubdetector;
26  import org.lcsim.geometry.subdetector.PolyconeSupport;
27  import org.lcsim.geometry.subdetector.SiTrackerBarrel;
28  import org.lcsim.geometry.subdetector.SiTrackerEndcap;
29  import org.lcsim.geometry.subdetector.SiTrackerEndcap2;
30  import org.lcsim.geometry.subdetector.TubeSegment;
31  
32  /**
33   * Convert a compact description to an html information page.
34   * 
35   * @author Jeremy McCormick <jeremym@slac.stanford.edu>
36   * @version $Id: HtmlConverter.java,v 1.8 2012/08/21 21:55:28 jeremy Exp $
37   */
38  // TODO add css
39  // TODO add converter for MultiLayerTracker to layer table
40  // TODO add Subdetectors by type lookup table
41  // TODO order of Subdetector details needs to make more sense; similar things together (readout, geom, etc.)
42  class HtmlConverter
43  {
44      static DecimalFormat layerForm = new DecimalFormat( "#.##" );
45      static DecimalFormat lenForm = new DecimalFormat( "#.######" );
46      static DecimalFormat geomForm = new DecimalFormat( "#.##");
47  
48      private HtmlConverter()
49      {}
50  
51      public static Element convert( Detector d )
52      {
53          // Convert to specific subclass for more method access.
54          Detector detector = ( org.lcsim.geometry.compact.Detector ) d;
55  
56          // Root element.
57          Element root = new Element( "html" );
58  
59          // Header.
60          Element head = new Element( "head" );
61          String detectorName = detector.getName();
62          Element title = new Element( "title" );
63          title.setText( detectorName );
64          head.addContent( title );
65          root.addContent( head );
66  
67          // Body.
68          Element body = new Element( "body" );
69          root.addContent( body );
70  
71          // Layout table.
72          Element tbl = new Element( "table" );
73          tbl.setAttribute( "cellspacing", "25" );
74          tbl.setAttribute( "width", "100%" );
75          body.addContent( tbl );
76  
77          // Layout row.
78          Element td = addLayoutRow( tbl );
79  
80          // Add detector header.
81          detectorHeader( td, detector );
82  
83          // Layout row.
84          td = addLayoutRow( tbl );
85  
86          // Links to defines and fields at bottom of page.
87          Element p = new Element( "p" );
88          p.addContent( new Link( "Go to Constants", "#defines" ) );
89          td.addContent( p );
90          p = new Element( "p" );
91          p.addContent( new Link( "Go to Fields", "#fields" ) );
92          td.addContent( p );
93  
94          // Sort subdetectors alphabetically.
95          List<String> subdets = new ArrayList<String>();
96          subdets.addAll( detector.getSubdetectors().keySet() );
97          java.util.Collections.sort( subdets );
98  
99          // Layout row.
100         td = addLayoutRow( tbl );
101 
102         // Add subdetector index.
103         subdetectorIndex( td, detector, subdets );
104 
105         // Layout row.
106         td = addLayoutRow( tbl );
107 
108         // Add system ID index.
109         sysIdIndex( td, detector );
110 
111         // Layout row.
112         td = addLayoutRow( tbl );
113 
114         // Add readout index.
115         readoutIndex( td, detector );
116 
117         // Layout row.
118         td = addLayoutRow( tbl );
119 
120         // Radiation and interaction lengths table.
121         lengthTable( td, detector, subdets );
122 
123         // Header for subdetector details section.
124         addHeader2( td, "Subdetector Details" );
125 
126         // Add subdetectors.
127         for ( String subdetName : subdets )
128         {
129             // Layout row.
130             td = addLayoutRow( tbl );
131 
132             // Add subdetector info.
133             subdetector( td, detector.getSubdetector( subdetName ) );
134         }
135 
136         // Layout row.
137         td = addLayoutRow( tbl );
138 
139         // Constants.
140         defines( td, detector );
141 
142         // Layout row.
143         td = addLayoutRow( tbl );
144 
145         // Fields.
146         fields( td, detector );
147 
148         // Layout row.
149         td = addLayoutRow( tbl );
150 
151         // Timestamp footer.
152         timestamp( td );
153 
154         return root;
155     }
156 
157     private static Element layers( Subdetector subdet )
158     {
159         Element tbl = null;
160         if ( subdet instanceof AbstractLayeredSubdetector )
161         {
162             AbstractLayeredSubdetector layered = ( AbstractLayeredSubdetector ) subdet;
163             LayerStack layers = layered.getLayering().getLayerStack();
164             if ( layers.getNumberOfLayers() > 0 )
165             {
166                 tbl = new Element( "table" );
167                 tbl.setAttribute( "border", "1" );
168 
169                 Layer currentLayer = null;
170                 int bottomLayer = 0;
171                 int topLayer = 0;
172                 for ( int i = 0, nlayers = layers.getNumberOfLayers(); i < nlayers; i++ )
173                 {
174                     if ( currentLayer == null )
175                     {
176                         currentLayer = layers.getLayer( i );
177                     }
178 
179                     // FIXME Use a better way than thickness to determine if different layer.
180                     if ( currentLayer.getThickness() != layers.getLayer( i )
181                             .getThickness() || i == nlayers - 1 )
182                     {
183                         if ( i == nlayers - 1 )
184                             topLayer = i;
185                         else 
186                             topLayer = i - 1;
187 
188                         // Special case of only one layer.
189                         if ( topLayer == -1 )
190                             topLayer = 0;
191 
192                         Element sliceTbl = new Element( "table" );
193                         sliceTbl.setAttribute( "cellpadding", "2" );
194 
195                         for ( LayerSlice slice : currentLayer.getSlices() )
196                         {
197                             addRow( sliceTbl,
198                                     layerForm.format( slice.getThickness() ) + " mm",
199                                     slice.getMaterial().getName(),
200                                     slice.isSensitive() ? new Element("i").addContent( "sensor") : " " );
201                         }
202 
203                         addRow( tbl, bottomLayer + " - " + topLayer, sliceTbl );
204 
205                         bottomLayer = i;
206                         topLayer = i;
207                         currentLayer = layers.getLayer( i );
208                     }
209                 }
210             }
211         }
212 
213         return tbl;
214     }
215 
216     private static void timestamp( Element parent )
217     {
218         Calendar cal = Calendar.getInstance();
219         SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
220         String ts = new String( "Generated by GeomConverter at " + sdf.format( cal
221                 .getTime() ) + " by user " + System.getProperty( "user.name" ) + "." );
222 
223         parent.addContent( new Element( "p" ).setText( ts ) );
224     }
225 
226     private static void lengthTable( Element parent,
227             Detector detector,
228             List<String> subdets )
229     {
230         // Header.
231         addHeader2( parent, "Radiation and Interaction Lengths" );
232 
233         Element tbl = new Element( "table" );
234         parent.addContent( tbl );
235         tbl.setAttribute( "border", "1" );
236         tbl.setAttribute( "cellpadding", "2" );
237 
238         // Table header row.
239         addRow( tbl, 
240                 new Element( "b" ).setText( "Subdetector" ), 
241                 new Element( "b" ).setText( "Radiation Lengths" ), 
242                 new Element( "b" ).setText( "Interaction Lengths" ) );
243 
244         for ( String subdetName : subdets )
245         {
246             Subdetector subdet = detector.getSubdetector( subdetName );
247             AbstractLayeredSubdetector layers;
248             if ( subdet instanceof AbstractLayeredSubdetector )
249             {
250                 layers = ( AbstractLayeredSubdetector ) subdet;
251                 addRow( tbl, 
252                         new Link( subdetName, "#" + subdetName ), 
253                         lenForm.format( layers.getRadiationLengths() ), 
254                         lenForm.format( layers.getInteractionLengths() ) );
255             }
256         }
257     }
258 
259     private static void sysIdIndex( Element parent, Detector detector )
260     {
261         // Header.
262         addHeader2( parent, "Subdetectors by System ID" );
263 
264         // Table
265         Element tbl = new Element( "table" );
266         tbl.setAttribute( "border", "1" );
267         tbl.setAttribute( "cellpadding", "2" );
268         parent.addContent( tbl );
269 
270         // Table header row.
271         addRow( tbl, new Element( "b" ).setText( "Sys Id" ), new Element( "b" )
272                 .setText( "Subdetector" ) );
273 
274         // Make system ID list, only including non-zero values.
275         List<Integer> systemIds = new ArrayList<Integer>();
276         for ( Subdetector subdet : detector.getSubdetectors().values() )
277         {
278             if ( subdet.getSystemID() != 0 )
279             {
280                 systemIds.add( subdet.getSystemID() );
281             }
282         }
283 
284         // Sort system ID list.
285         java.util.Collections.sort( systemIds );
286 
287         for ( Integer sysId : systemIds )
288         {
289             Subdetector subdet = detector.getSubdetector( sysId );
290             String subdetName = subdet.getName();
291             addRow( tbl, subdet.getSystemID(), new Link( subdetName, "#" + subdetName ) );
292         }
293     }
294 
295     private static void subdetectorIndex( Element parent,
296             Detector detector,
297             List<String> names )
298     {
299         // Header.
300         addHeader2( parent, "Components" );
301 
302         // Table.
303         Element tbl = new Element( "table" );
304         tbl.setAttribute( "border", "1" );
305         tbl.setAttribute( "cellpadding", "2" );
306         parent.addContent( tbl );
307 
308         // todo: addHeaderRow method
309         addRow( tbl, new Element( "b" ).setText( "Subdetector" ) );
310 
311         for ( String subdetName : names )
312         {
313             Subdetector subdet = detector.getSubdetector( subdetName );
314             String readoutName = "-";
315             if ( subdet.getReadout() != null )
316             {
317                 readoutName = subdet.getReadout().getName();
318             }
319 
320             addRow( tbl, new Link( subdetName, "#" + subdetName ) );
321         }
322     }
323 
324     private static void readoutIndex( Element parent, Detector detector )
325     {
326         // Header.
327         addHeader2( parent, "Readouts" );
328 
329         // Table
330         Element tbl = new Element( "table" );
331         tbl.setAttribute( "border", "1" );
332         tbl.setAttribute( "cellpadding", "2" );
333         parent.addContent( tbl );
334 
335         // Table header row.
336         addRow( tbl, 
337                 new Element( "b" ).setText( "Readout" ), 
338                 new Element( "b" ).setText( "Subdetectors" ),
339                 new Element( "b" ).setText( "ID Description" ),
340                 new Element( "b" ).setText( "Cell Size U x V" ));
341 
342         // Alpha sort on readout name.
343         List<String> readoutNames = new ArrayList<String>( detector.getReadouts()
344                 .keySet() );
345         java.util.Collections.sort( readoutNames );
346 
347         // Process Readouts by name.
348         for ( String readoutName : readoutNames )
349         {
350             // Get the Readout.
351             Readout readout = detector.getReadout( readoutName );
352 
353             // Get the list of Subdetectors.
354             List<Subdetector> subdets = new ArrayList<Subdetector>();
355 
356             // Make list of associated Subdetectors.
357             Element span = new Element( "span" );
358             for ( Subdetector subdet : detector.getSubdetectors().values() )
359             {
360                 // Check if Readout matches.
361                 if ( subdet.getReadout() == readout )
362                 {
363                     String subdetName = subdet.getName();
364                     span.addContent( new Link( subdetName, "#" + subdetName ) );
365                 }
366             }
367             
368             String cellSizes = "NA";
369             try 
370             {
371                 if ( readout.getIDDecoder() instanceof Segmentation )
372                 {
373                     Segmentation seg = (Segmentation) readout.getIDDecoder();
374                     cellSizes = seg.getCellSizeU() + " mm x " + seg.getCellSizeV() + " mm";
375                 }
376             }
377             catch ( Exception x )
378             {
379                 // Ignore.
380             }
381 
382             // Add row for this Readout.
383             addRow( tbl, 
384                     readout.getName(), 
385                     span, 
386                     readout.getIDDecoder().getIDDescription().toString(),
387                     cellSizes );
388         }
389     }
390 
391     private static void detectorHeader( Element parent, Detector detector )
392     {
393         addHeader2( parent, "Summary" );
394 
395         Element tbl = new Element( "table" );
396         tbl.setAttribute( "border", "1" );
397         tbl.setAttribute( "cellpadding", "2" );
398         parent.addContent( tbl );
399 
400         Header header = detector.getHeader();
401 
402         addLabeledRow( tbl, "Detector", detector.getName() );
403         addLabeledRow( tbl, "Title", header.getTitle() );
404         addLabeledRow( tbl, "Comment", header.getComment() );
405         addLabeledRow( tbl, "Author", header.getAuthor() );
406         addLabeledRow( tbl, "Status", header.getStatus() );
407         addLabeledRow( tbl, "Version", header.getVersion() );
408         addLabeledRow( tbl,
409                 "Documentation",
410                 header.getURL().equals( "NONE" ) ? "NONE" : new Link( header.getURL() ) );
411         addLabeledRow( tbl,
412                 "Zip File",
413                 new Link( "http://www.lcsim.org/detectors/" + detector.getName() + ".zip" ) );
414     }
415 
416     private static void subdetector( Element parent, Subdetector subdet )
417     {
418         // Make bookmark in page.
419         bookmark( parent, subdet.getName() );
420 
421         // Subdetector data table.
422         Element tbl = new Element( "table" );
423         tbl.setAttribute( "border", "1" );
424         tbl.setAttribute( "width", "80%" );
425         tbl.setAttribute( "cellpadding", "2" );
426         parent.addContent( tbl );
427 
428         // Basic info.
429         addLabeledRow( tbl, "Subdetector", subdet.getName() );
430         addLabeledRow( tbl, "System ID", subdet.getSystemID() );
431         addLabeledRow( tbl, "Type", subdet.isCalorimeter() ? "Calorimeter" : "Tracker" );
432         addLabeledRow( tbl, "Class", subdet.getClass().getSimpleName() );
433         addLabeledRow( tbl, "Endcap", subdet.isEndcap() ? true : false );
434         addLabeledRow( tbl, "Readout", subdet.getReadout() != null ? subdet.getReadout()
435                 .getName() : "NONE" );
436         addLabeledRow( tbl, "Tracking Vol", subdet.isInsideTrackingVolume() );
437         addLabeledRow( tbl, "ID Description", subdet.getReadout() != null ? subdet
438                 .getIDDecoder().getIDDescription().toString() : "NONE" );
439 
440         if ( subdet instanceof AbstractLayeredSubdetector )
441         {
442             AbstractLayeredSubdetector layers = ( AbstractLayeredSubdetector ) subdet;
443 
444             addLabeledRow( tbl, "Number Of Layers", layers.getNumberOfLayers() );
445             addLabeledRow( tbl, "Interaction Lengths", lenForm.format( layers.getInteractionLengths() ) );
446             addLabeledRow( tbl, "Radiation Lengths", lenForm.format( layers.getRadiationLengths() ) );
447         }
448 
449         // Calorimeter info.
450         if ( subdet instanceof Calorimeter )
451         {
452             Calorimeter cal = ( Calorimeter ) subdet;
453             addLabeledRow( tbl, "Calorimeter Type", cal.getCalorimeterType().toString() );
454             addLabeledRow( tbl, "Number Of Sides", cal.getNumberOfSides() );
455             addLabeledRow( tbl, "Inner Radius", geomForm.format( cal.getInnerRadius() ) + " mm" );
456             addLabeledRow( tbl, "Outer Radius", geomForm.format( cal.getOuterRadius() ) + " mm" );
457             addLabeledRow( tbl, "Z Length", geomForm.format( cal.getZLength() ) + " mm" );
458             addLabeledRow( tbl, "Inner Z", geomForm.format( cal.getInnerZ() ) + " mm" );
459             addLabeledRow( tbl, "Outer Z", geomForm.format( cal.getOuterZ() ) + " mm" );
460             addLabeledRow( tbl, "Section Phi", geomForm.format( cal.getSectionPhi() ) + " radians" );
461             if ( subdet.getReadout() != null && subdet.getReadout().getIDDecoder() instanceof Segmentation )
462             {
463                 Segmentation seg = ( Segmentation ) subdet.getReadout().getIDDecoder();
464                 addLabeledRow( tbl, "Segmentation Type", seg.getClass().getSimpleName() );
465             }
466 
467             try
468             {
469                 addLabeledRow( tbl, "Cell Size U", subdet.getReadout() != null ? cal
470                         .getCellSizeU() + " mm" : "NA" );
471                 addLabeledRow( tbl, "Cell Size V", subdet.getReadout() != null ? cal
472                         .getCellSizeV() + " mm" : "NA" );
473             }
474             catch ( IndexOutOfBoundsException x )
475             {
476                 // This can happen sometimes with a few types of Segmentation that have no
477                 // cell U/V defined.
478             }
479 
480             // Layering information.
481             if ( subdet.getLayering() != null && subdet.getLayering().getNumberOfLayers() > 0 )
482             {
483                 Element layerTbl = layers( subdet );
484 
485                 addLabeledRow( tbl, "Layers", layerTbl );
486             }
487         }
488         else if ( subdet instanceof TubeSegment )
489         {
490             TubeSegment tube = (TubeSegment) subdet;
491             addLabeledRow( tbl, "Inner Radius", geomForm.format( tube.getInnerRadius() ) + " mm" );
492             addLabeledRow( tbl, "Outer Radius", geomForm.format( tube.getOuterRadius() ) + " mm" );
493             addLabeledRow( tbl, "Z Half Length", geomForm.format( tube.getZHalfLength() ) + " mm" );
494         }
495         else if ( subdet instanceof PolyconeSupport )
496         {
497             Element planesTbl = new Element("table");
498             planesTbl.setAttribute( "border", "1" );
499             planesTbl.setAttribute( "cellpadding", "2");
500             
501             PolyconeSupport poly = (PolyconeSupport) subdet;
502             
503             // Table header row.
504             addRow( planesTbl, 
505                     new Element( "b" ).setText( "R Min" ), 
506                     new Element( "b" ).setText( "R Max" ),
507                     new Element( "b" ).setText( "Z" ) );
508             
509             for ( int i = 0, nplanes = poly.getNumberOfZPlanes(); i < nplanes; i++ )
510             {
511                 addRow( planesTbl, 
512                         geomForm.format( poly.getZPlane( i ).getRMin() ),
513                         geomForm.format( poly.getZPlane( i ).getRMax() ),
514                         geomForm.format( poly.getZPlane( i ).getZ() )  );
515             }
516             
517             addLabeledRow( tbl, "Z Planes", planesTbl );
518         }
519         // TODO Need "default" setup to get detailed tracking parameters (strip pitches, etc.).
520         else if ( subdet instanceof SiTrackerBarrel || subdet instanceof SiTrackerEndcap || subdet instanceof SiTrackerEndcap2)
521         {            
522             IDetectorElement de = subdet.getDetectorElement();
523 
524             List<SiSensor> sensors = de.findDescendants( SiSensor.class );            
525             int nsensors = sensors.size();      
526                                    
527             addLabeledRow( tbl, "Sensors", Integer.toString( nsensors ) );
528         }
529     }
530 
531     private static void defines( Element parent, Detector detector )
532     {
533         bookmark( parent, "defines" );
534 
535         addHeader2( parent, "Constants" );
536 
537         Element tbl = new Element( "table" );
538         tbl.setAttribute( "border", "1" );
539         tbl.setAttribute( "width", "50%" );
540         tbl.setAttribute( "cellpadding", "1" );
541         parent.addContent( tbl );
542 
543         // Alpha sort.
544         Map<String, Constant> cmap = detector.getConstants();
545         List<String> constants = new ArrayList<String>( cmap.keySet() );
546         java.util.Collections.sort( constants );
547 
548         for ( String key : constants )
549         {
550             addLabeledRow( tbl, key, cmap.get( key ).getValue() );
551         }
552     }
553 
554     private static void fields( Element parent, Detector detector )
555     {
556         bookmark( parent, "fields" );
557 
558         addHeader2( parent, "Fields" );
559 
560         Element tbl = new Element( "table" );
561         parent.addContent( tbl );
562         tbl.setAttribute( "border", "1" );
563         tbl.setAttribute( "width", "50%" );
564 
565         for ( Map.Entry<String, Field> entry : detector.getFields().entrySet() )
566         {
567             Field field = entry.getValue();
568             addLabeledRow( tbl, "Field", entry.getKey() );
569             addLabeledRow( tbl, "Type", field.getClass().getSimpleName() );
570             if ( field instanceof Solenoid )
571             {
572                 Solenoid solenoid = ( Solenoid ) field;
573                 addLabeledRow( tbl, "Inner Field", solenoid.getInnerField()[ 2 ] + " Tesla" );
574                 addLabeledRow( tbl, "Outer Field", solenoid.getOuterField()[ 2 ] + " Tesla" );
575                 addLabeledRow( tbl, "Z Max", solenoid.getZMax() + " mm" );
576                 addLabeledRow( tbl, "Outer Radius 2", solenoid.getOuterRadius2() + " mm" );
577             }
578         }
579     }
580 
581     private static void addHeader2( Element parent, String text )
582     {
583         Element h = new Element( "h2" );
584         h.setText( text );
585         parent.addContent( h );
586     }
587 
588     private static Element addLayoutRow( Element tbl )
589     {
590         Element tr = new Element( "tr" );
591         tbl.addContent( tr );
592         Element td = new Element( "td" );
593         tr.addContent( td );
594         return td;
595     }
596 
597     private static void addRow( Element table, Object... values )
598     {
599         if ( !table.getName().equals( "table" ) )
600         {
601             throw new RuntimeException( "Element is not a <table>." );
602         }
603 
604         Element tr = new Element( "tr" );
605         table.addContent( tr );
606 
607         for ( Object value : values )
608         {
609             Element td = new Element( "td" );
610             td.setAttribute( "valign", "top" );
611             if ( value instanceof String )
612                 td.setText( ( String ) value );
613             else if ( value instanceof Element )
614                 td.addContent( ( Element ) value );
615             else
616                 td.setText( value.toString() );
617             tr.addContent( td );
618         }
619     }
620 
621     private static void addLabeledRow( Element table, String label, Object value )
622     {
623         if ( !table.getName().equals( "table" ) )
624         {
625             throw new RuntimeException( "Element is not a <table>." );
626         }
627 
628         Element tr = new Element( "tr" );
629         table.addContent( tr );
630 
631         // Label.
632         Element td = new Element( "td" );
633         td.setAttribute( "width", "25%" );
634         td.setAttribute( "valign", "top" );
635         Element b = new Element( "b" );
636         td.addContent( b );
637         b.setText( label );
638         tr.addContent( td );
639 
640         // Value.
641         td = new Element( "td" );
642         td.setAttribute( "valign", "top" );
643         tr.addContent( td );
644         if ( value instanceof String )
645             td.setText( ( String ) value );
646         else if ( value instanceof Element )
647             td.addContent( ( Element ) value );
648         else
649             td.setText( value.toString() );
650     }
651 
652     private static void bookmark( Element parent, String text )
653     {
654         Element a = new Element( "a" );
655         a.setAttribute( "name", text );
656         parent.addContent( a );
657     }
658 
659     private static class Link extends Element
660     {
661         Link( String label, String url )
662         {
663             super( "a" );
664             this.setAttribute( "href", url );
665             this.setText( label );
666         }
667 
668         Link( String url )
669         {
670             super( "a" );
671             this.setAttribute( "href", url );
672             this.setText( url );
673         }
674     }
675 }