make_refactored_gdml.pl
Go to the documentation of this file.
1 #!/usr/bin/perl
2 # Heavily revised Jan-2010 <seligman@nevis.columbia.edu>
3 
4 #
5 # Build a description of the detectors from gdml fragments
6 #
7 
8 # Use the command line arguments to give us the list of file fragments
9 # that we'll zip together. The man page for 'GetOptions' can be read
10 # with: perldoc Getopt::Long
11 
12 use Getopt::Long;
13 GetOptions( "input|i:s" => \$input,
14  "help|h" => \$help,
15  "output|o:s" => \$output);
16 
17 if ( defined $help )
18 {
19  # If the user requested help, print the usage notes and exit.
20  usage();
21  exit;
22 }
23 
24 if ( ! defined $input )
25 {
26  # If the user has not used "-i", then just take the first
27  # non-option argument.
28  if ( $#ARGV > -1 )
29  {
30  $input = $ARGV[0];
31  if ( ! -r $input )
32  {
33  print "Input file $input not found\n";
34  usage();
35  exit;
36  }
37  }
38  else
39  {
40  # Read from STDIN
41  $input = "-";
42  }
43 }
44 else
45 {
46  # The "-i" option was provided; check that the input file exists.
47  if ( ! -r $input )
48  {
49  print "Input file $input not found or cannot be read\n";
50  usage();
51  exit;
52  }
53 }
54 
55 if ( ! defined $output )
56 {
57  $output = "-"; # write to STDOUT
58 }
59 
60 # Read the list of file fragments from an XML-formatted file.
61 # (Type "perldoc XML::LibXML" for how to use this package.)
62 
63 use XML::LibXML;
64 # Create an XML parser.
65 $parser = new XML::LibXML;
66 
67 # Read the XML file. The entire contents are slurped into a DOM
68 # structure.
69 $dom = $parser->parse_file($input);
70 
71 # Note that @defFiles and @gdmlFiles are both arrays of "nodes".
72 @defFiles = $dom->findnodes('/config/constantfiles/filename');
73 @gdmlFiles = $dom->findnodes('/config/gdmlfiles/filename');
74 
75 # Keep track of how many constants we read in.
76 $numberConstants = -1;
77 
78 # Developer note: If I were slicker, I'd also use XML::LibXML to read
79 # in these GDML fragments. However, the files would have to be edited
80 # to be strict XML, and that's more effort than it's worth. The script
81 # generate_gdml.pl writes strict XML documents, but there's no
82 # guarantee that this program will be used just with those
83 # files.
84 
85 #
86 # Build the table of variable replacements
87 #
88 
89 # For each node that represents a file of constants...
90 foreach $filename (@defFiles)
91 {
92  $CONSTANTS = $filename->to_literal;
93  open(CONSTANTS) or die("Could not open file $CONSTANTS");
94 
95  # For each line in the file...
96  foreach $line (<CONSTANTS>)
97  {
98  # Find the name and value as defined in a <constant> block; e.g.:
99  # <constant name="kInch" value="2.54" />
100  # will be parsed as $name="kInch" and value = "2.54"
101 
102  # If the line begins with "<constant"...
103  if ( $line =~ /^\s*<constant / )
104  {
105  # (See "perldoc perlfaq6" for the definition of a non-greedy search.)
106  # Do a "non-greedy" search to get the text assigned to 'name'
107  $line =~ /name="(.*?)"/;
108  $name = $1;
109  # Do a "non-greedy" search to get the text assigned to 'value'
110  $line =~ /value="(.*?)"/;
111  $value = $1;
112 
113  # Append to the list of constants. Put parenthesis around
114  # the value, to avoid potential problems with arithmetic.
115  ++$numberConstants;
116  $name[$numberConstants] = $name;
117  $value[$numberConstants] = "($value)";
118  # print "$numberConstants: $name = $value[$numberConstants]\n"; # debug
119  }
120  }
121  close(CONSTANTS);
122 }
123 
124 # The main GDML keywords, used in tags. The order here is important:
125 # No matter what order these blocks are in the sub-files, this is the
126 # order in which they must be written in the final GDML output.
127 
128 # If I were being super-slick, I'd use the features of LibXML to read
129 # each of these GDML sub-files, then fiddle with the elements using
130 # XML manipulation routines. However, it's much simpler to treat them
131 # as big globs of text.
132 
133 @keywords = qw( extension define materials solids structure );
134 
135 # For each node that's a file of GDML statements...
136 foreach $filename ( @gdmlFiles )
137 {
138 
139  # Open the file.
140  $FILE = $filename->to_literal;
141  open(FILE) or die("Could not open file $FILE for read.");
142 
143  # Read the entire file into an array.
144  @file = <FILE>;
145  close(FILE);
146 
147  # Slurp the array into a single variable.
148  $file = join("",@file);
149 
150  foreach $keyword ( @keywords )
151  {
152  # Search the file for a keyword block. For example, if
153  # $keyword were "blorg", the following would search for
154  # <blorg>some text</blorg> and snip it out of $file.
155  while ( $file =~ s/(.*)<$keyword>(.*?)<\/$keyword>(.*)/\1\3/s )
156  {
157  # Following the above example, this would append "some
158  # text" to $keyhash{blorg}
159 
160  $keyhash{$keyword} = $keyhash{$keyword} . $2;
161  }
162  }
163 }
164 
165 # Write the final GDML file.
166 
167 $OUTPUT = ">" . $output;
168 open(OUTPUT) or die("Could not open $output for writing");
169 
170 # The preliminary material for the GDML file. This defines the GDML
171 # schema and namespaces.
172 
173 print OUTPUT <<EOF;
174 <?xml version="1.0" encoding="UTF-8" ?>
175 <gdml_simple_extension xmlns:gdml_simple_extension="http://www.example.org"
176  xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
177  xs:noNamespaceSchemaLocation="RefactoredGDMLSchema/SimpleExtension.xsd">
178 
179 
180 EOF
181 # Print to OUTPUT all the GDML sections, with each set of tags
182 # unified, in the appropriate order.
183 
184 foreach $keyword ( @keywords )
185 {
186  print OUTPUT "<$keyword>";
187 
188  # Substitute any constants in the GDML with their numeric
189  # equivalents.
190 
191  # In strict GDML, this should not be necessary; according to the
192  # specification, you should be able to define a constant and use
193  # it in subsequent GDML statements. If you use the standard GDML
194  # parser, this not a problem. ROOT, however, uses its own parser,
195  # and (as of ROOT 5.16) it could not handle variables in GDML
196  # expressions. So here we side-step the problem by performing our
197  # own substitutions.
198 
199  # Step through this list of constants in reverse order, to resolve
200  # any dependencies.
201 
202  for ( $i = $numberConstants; $i >= 0; --$i )
203  {
204  $keyhash{$keyword} =~ s/$name[$i]/$value[$i]/g;
205  }
206 
207  # Print the edited section.
208  print OUTPUT $keyhash{$keyword};
209 
210  print OUTPUT "</$keyword>\n";
211 }
212 
213 # The final section of a GDML file is the <setup></setup> section. At
214 # present, we don't define alternate setups in the same GDML file, so
215 # these lines are constant.
216 
217 print OUTPUT <<EOF;
218 
219  <setup name="Default" version="1.0">
220  <world ref="volWorld"/>
221  </setup>
222 
223 </gdml_simple_extension>
224 EOF
225 
226 close(OUTPUT);
227 
228 
229 sub usage()
230 {
231  print "Usage: $0 [-h|--help] [-i|--input <xml-fragments-file>] [-o|--output <output-file>]\n";
232  print " -i/--input can be omitted; if no input file, defaults to STDIN\n";
233  print " if -o is omitted, output goes to STDOUT\n";
234  print " -h prints this message, then quits\n";
235 }