/* This tutorial ddl file defines the data structures for a toy Monte Carlo program. The toy Monte Carlo program will produce a data file called a GAF (Generic Adamo File), using the data structures defined here. The GAF is organized into RECORDS. For our Monte Carlo program, each record will correspond to an event. Below, you're going to define a series of tables (ESETS) and the relationships between them (RSETS). You will group the tables and relationships into larger units called DATAFLOWS, and one overall unit called a SUBSCHEMA. The information for each Monte Carlo event will be stored in these data structures. Each new record (event) represents a whole new set of table data. */ /* ------------------------------------------------------------------------ */ /* A FEW COMMENTS ABOUT DDL */ /* ------------------------------------------------------------------------ */ /* - DDL is a completely free-format language, like C, in the sense that line breaks in the source are irrelevant, you can put them anywhere. - The order of your ESET, RSET, etc ... definitions is also irrelevant. You can define a few ESETs (tables), then some RSETs (relationships), then a few more ESETs, an ATTRIBUTE, a DATAFLOW, etc ... in any order you wish. - What you are reading now is a comment, obviously. As you see, the comment specifiers are the same as in C. These comments will be completely ignored by any program that uses this ddl file. - You will see below that you can also include 'formal comments'. These are character strings framed by single quotes, and introduced by a colon (:). These formal comments WILL be stored when the DDL file is processed. */ /* ------------------------------------------------------------------------ */ /* START A SUBSCHEMA */ /* ------------------------------------------------------------------------ */ /* You have to declare a subschema first. The name of the subschema is */ /* never used anywhere that I can tell. One subschema per ddl file is */ /* normal. The AUTHOR bit is optional, and you can also add other bits like */ /* a version number ... see the ADAMO Reference Guide. */ /* The only important thing about a subschema is that it is SELF-CONTAINED. */ /* If you have only on subschema, this is irrelevant. But if you have more */ /* than one, it just means that no relationships or dataflows can cross */ /* a subschema boundary by referring to objects in another subschema. */ /* But please note: it is REQUIRED that all DDL code be contained within */ /* a subschema. */ SUBSCHEMA MarvinSlotman AUTHOR 'If anyone knows THAT popculture reference, call me' /* ------------------------------------------------------------------------ */ /* DEFINE THE KEY TABLE */ /* ------------------------------------------------------------------------ */ /* You're going to need a key table. This special table must contain enough */ /* information to uniquely identify each record in your GAF. Since our */ /* records correspond to Monte Carlo events, let's include an event number */ /* in the key table. We'll also throw in a run number, in case multiple */ /* runs are combined later on into one big GAF. Finally, every key table */ /* MUST have a 32-character variable as its last entry. When writing to or */ /* reading from a GAF, you not only have to specify which record you want, */ /* but also which dataflow. The 32-character variable will be used to */ /* specify the dataflow name. */ DEFINE ESET mcEvKey =( iEvent = INTE [1,*] : 'Event Number', iRun = INTE [1,*] : 'Run Number', cName = CH32 : 'Dataflow names will go here') : 'Key table for Monte Carlo event generation'; END ESET /* We will use mcEvKey as our key table later on, but from the DDL point */ /* of view, it's just an ordinary table. So, a few remarks about tables: */ /* - DEFINE ESET and END ESET are DDL directives which tell the ddl */ /* processor (called MAD) that the statements in between are table */ /* definitions. ESET means 'Entity Set' which is ADAMO jargon for */ /* a table. */ /* - Everything between 'DEFINE ESET' and 'END ESET' in this example */ /* is one ddl statement. As in C, each statement is terminated by */ /* a semi-colon (;) */ /* - mcEvKey is the name of the table */ /* - iEvent, iRun, and cName are COLUMN names. For now, just think of */ /* them as the variables within the table. In fact, that is exactly */ /* what they will become: program variables that you can access. */ /* In FORTRAN, column iEvent of table mcEvKey will be accessible */ /* via an integer variable called 'mcEvKey_iEvent' (you'll see). */ /* In C, the variable name would be 'mcEvKey.iEvent'. In Fortran, */ /* the table itself will be a common block: /mcEvKey/. The variables */ /* mcEvKey_iEvent, mcEvKey_iRun, and mcEvKey_cName will be members */ /* of that common block. In C, mcEvKey is a structure rather than */ /* a common block. Like I say, you'll see ... */ /* - INTE and CH32 specify the variable type. Common types are: */ /* REAL = real */ /* INTE = integer */ /* BITP = bitpattern (basically, also an integer variable) */ /* CHA4 = character string of length 4 */ /* CHA8 = character string of length 8 */ /* CH16 = character string of length 16 */ /* CH32 = character string of length 32 */ /* CH64 = character string of length 64 */ /* - [1,*] is an optional range specifier. If certain types of */ /* checking are turned on in your program, ADAMO will take care that */ /* all values loaded to your variables are within the range you */ /* specified in the DDL. In this case, [1,*] means that the event */ /* and run numbers must be greater than or equal to 1, but can be */ /* arbitrarily large. Again, such checking is only done if you */ /* specifically request it in your program. Otherwise these ranges */ /* are ignored ... with one exception, which you will see in */ /* a moment. */ /* ------------------------------------------------------------------------ */ /* DEFINE SOME ATTRIBUTES */ /* ------------------------------------------------------------------------ */ /* Attributes are basically extensions of the variable types presented */ /* above (INTE, REAL, ...): they are customized variable types. You don't */ /* need to define ANY attributes if you don't want to. But if you want to */ /* use ADAMO's internal range checking features, you can set the range */ /* once and for all for certain types of information, and define an */ /* attribute to reflect that. Here, we will define three 'customized' */ /* versions of REAL: */ /* - 'Momentum' cannot be negative, and must be below 100 GeV/c */ /* - 'Energy' cannot be negative, and must be below 100 GeV */ /* - 'Coordinate' must specify a point within 10 km of the origin :) */ DEFINE ATTRIBUTE Momentum = REAL [0.000,100.] : 'momentum in GeV/c'; Energy = REAL [0.000,100.] : 'energy in GeV'; Coordinate = REAL [-1000000.000,1000000.000] : 'position in cm'; END ATTRIBUTE /* At this point, I'll mention the other significance of range specifiers. */ /* Even if range checking is turned off in your program, ADAMO consults */ /* these specifiers to determine the PRECISION (number of significant */ /* digits) with which it should DISPLAY the values of your variables. */ /* ADAMO has various routines which allow you to easily print out the */ /* currently stored in your tables. The MAXIMAL number of significant */ /* digits appearing in the variable's range specifier is used. So in this */ /* example, we are telling ADAMO to always print out Momentum, Energy, and */ /* Coordinate variables with 3 significant digits. */ /* Just as an example, you can also specify a LIST of acceptable values */ /* rather than a range. This if often done for character string variables. */ /* In this case, you do not need the range specifiers [], but rather the */ /* Boolean OR operator '|'. These two pieces of DDL code are equivalent: */ /* */ /* DEFINE ESET */ /* mcEvent = (cType = CHA4 'DIS'|'BACK'); */ /* END ESET */ /* */ /* DEFINE ATTRIBUTE EventType = 'DIS'|'BACK'; END ATTRIBUTE */ /* DEFINE ESET mcEvent = (cType = EventType); END ESET */ /* ------------------------------------------------------------------------ */ /* DEFINE YOUR TABLES */ /* ------------------------------------------------------------------------ */ /* OK, more table definitions. I'll make some remarks here and there. */ DEFINE ESET /* Table mcEvent records basic information about the primary scattering */ /* vertex: the kinematic variables Nu and Q2. Note the use of the 'Energy' */ /* attribute defined previously. */ mcEvent = ( Nu= Energy : 'nu = E - Eprime', Q2= REAL [0.000,1000.] : 'inv. momentum exchange Q**2') :'Monte Carlo event information'; /* Table mcBeam records the beam energy and the position of the hard */ /* scattering vertex within the target for each event. */ mcBeam = ( ZVx = Coordinate :'z-vertex', EBe = Energy :'beam energy') :'beam and vertex information'; /* Table mcTrack is the first one we have encountered so far that will in */ /* general have more than one ROW per event. In each event, there can be */ /* many particle tracks! The table nature of mcTrack now becomes important: */ /* each row of the table will represent one track. Each row will contain */ /* three values, one for each COLUMN defined below. */ mcTrack = ( iCharge = INTE [-1,1] : 'particle charge', cName = CHA4 : '4-character name of particle', P = Momentum : 'momentum') : 'Monte Carlo tracks'; /* Table mcVert will contain space points. As you will see, we will */ /* associate some of these locations in space with each track. */ /* Specifically, each track will be associated with one starting point */ /* and one stopping point. */ mcVert = ( X = Coordinate :'x-vertex', Y = Coordinate :'y-vertex', Z = Coordinate :'z-vertex') :'track vertices'; /* Table mcHit also records space points. However, these represent the */ /* points at which particle tracks passed through the sensitive detectors */ /* of our spectrometer, producing HITS. We store the position of each hit. */ mcHit = ( X=Coordinate : 'x-Coordinate', Y=Coordinate : 'y-Coordinate', Z=Coordinate : 'z-Coordinate') : 'Monte Carlo hit information'; /* Finally, this set of three tables will store the detector responses */ /* calculated for each hit. In Monte Carlo jargon, these detector responses */ /* are called 'digitized hits', or simply 'digitizations'. If the hit is in */ /* a wire chamber, the digitization info will show up in table dataPuls. */ /* Hodoscope ditizations show up in dataHodo, and calorimeter responses go */ /* to dataCalo. We need three different tables here because the different */ /* detector types record different types of information. In this example: */ /* - wire chambers record which wire was hit and the time of the hit */ /* (as measured by a TDC) */ /* - hodoscopes record both ADC and TDC values, as well as the paddle */ /* number which was hit (also called iWire, for convenience) */ /* - the calorimeter records a cell number, and an energy deposit */ dataPuls = ( iWire = INTE[1,*] : 'wire number which fired', iTDC = INTE : 'TDC value', cName = CHA4 : 'detector name' ): 'wire chamber digitizations'; dataHodo = ( iWire = INTE[1,*] : 'paddle number which fired', iADC = INTE : 'ADC value', iTDC = INTE : 'TDC value', cName = CHA4 : 'detector name' ): 'hodoscope digitizations'; dataCalo = ( iCell = INTE[1,420] : 'Cell of Calorimeter or Lumi', rPuls = REAL : 'Energy Deposit in Cell', cName = CHA4 : 'detector name' ): 'calorimeter digitizations'; /* We're finished with table definitions. */ END ESET /* ------------------------------------------------------------------------ */ /* DEFINE RELATIONSHIPS BETWEEN THE TABLES */ /* ------------------------------------------------------------------------ */ /* It is now time to establish the relationships, or links, between the */ /* tables we have just defined. In this tutorial, we try to include */ /* examples of all the common relationship types. */ /* A relation can also be called a link. It links, or associates, the */ /* information in each ROW of one table to the information in some row */ /* of ANOTHER table. */ /* A couple of general remarks about relationships: */ /* - Relationship definitions are framed by the DDL instructions */ /* 'DEFINE RSET' and 'END RSET'. */ /* - It is perfectly OK to have a table without any relationship. */ DEFINE RSET /* Here is the simplest type of relationship: each event is associated */ /* with some beam parameters. So we make a link from table mcEvent */ /* to table mcBeam. */ (mcEvent [1,1] -> [1,1] mcBeam); /* OK, what did we just do? This is a pretty useless relationship, since */ /* the mcEvent and mcBeam tables are only going to have one row per event, */ /* so they are ALREADY pretty obviously related. Anyway ... */ /* What we just did was basically add another variable, or COLUMN, to the */ /* mcEvent table. In FORTRAN terms, the /mcEvent/ common block just got */ /* another member: mcEvent_mcBeam. For each row in mcEvent, this variable */ /* will store the number of row in mcBeam to which it is related. */ /* Since both tables will only contain one row, this is really silly. */ /* Variable mcEvent_mcBeam will always contain the number 1. */ /* So what is up with the [1,1] designations? In ADAMO jargon, these are */ /* called CARDINALITIES, and are very similar to the range specifications */ /* we saw earlier. The [1,1] on the left hand side means this: for each */ /* mcEvent row, how many links can we have TO this row, from the mcBeam */ /* table? We have specified 'exactly one': every event MUST have one and */ /* only one set of beam parameters. The [1,1] on the right hand side asks */ /* the same question from the mcBeam side: for each row in mcBeam, how many */ /* links TO this row can we have from mcEvent? Again, one and only one. */ /* In ADAMO jargon, this is called a one-to-one relationship. */ /* OK, on to the next relationship ... */ (mcTrack [0,1] -> [0,*] mcTrack BY Parent) :'Primary tracks may have parent tracks'; /* This declaration is linking each row of mcTrack to ANOTHER row of */ /* mcTrack. What we are trying to do here is relate the decay products of */ /* unstable particles to their 'parents'. For example, a K0_s particle */ /* might be generated by the Monte Carlo. This particle will get an entry */ /* (row) in mcTrack. After some time, the K0_s will decay into two pions. */ /* These pions will also get entries in mcTrack. We would like to record */ /* this information, by LINKING the decay pions to their parent particle. */ /* The 'BY Parent' specifier is new. All this does is RENAME the link. */ /* If 'BY Parent' were omitted, common block /mcTrack/ would get a new */ /* relationship variable called mcTrack_mcTrack. That might be confusing. */ /* We choose instead to rename the link to 'Parent' ... the relationship */ /* variable will now be called mcTrack_Parent. */ /* Now, about the cardinalities of this link. On the left hand side, [0,1] */ /* means this: for each track (row) in mcTrack, we can have at most one */ /* link to a Parent track. Zero links is OK (many particles are NOT decay */ /* products, and have no parents). On the right hand side, [0,*] means */ /* this: each row in mcTrack can have any number (0 to infinity) of links */ /* TO IT via the Parent relationship. In other words, a given track may or */ /* may not be a parent (an unstable particle with decay products). If it */ /* is, it could have any number of decay products. */ (mcTrack [1,1] -> [1,*] mcVert BY startVert) :'Monte carlo tracks start somewhere'; (mcTrack [1,1] -> [1,*] mcVert BY stopVert) :'Monte carlo tracks stop somewhere'; /* These relationships illustrate the importance of named links, via the */ /* 'BY' keyword. We want to link rows from mcTrack to rows from the mcVert */ /* spacepoint table. Why? We would like to record the spacepoints at which */ /* each track started and stopped. If we didn't have the BY keyword at all, */ /* both of these links would be called 'mcTrack_mcVert' and we would have */ /* a conflict. Using named links, we can specify two separate links to */ /* mcVert: mcTrack_startVert and mcTrack_stopVert. */ (mcHit [1,1] -> [0,*] mcTrack) :'Monte carlo tracks have hits'; /* Nothing special here. Each hit is related to exactly one track. */ /* (Otherwise, what would have created the hit? Only particle tracks can */ /* cause a hit.) Meanwhile, tracks may or may not have caused any hits in */ /* sensitive detectors. They may have missed the detectors completely ... */ (mcHit [1,1] -> [1,1] dataPuls | -> [1,1] dataHodo | -> [1,1] dataCalo BY digiTable) : 'Hits are digitized'; /* Finally we come to GENERALIZED RELATIONSHIPS. Each hit is associated */ /* with one and only one digitization = calculated detector response. */ /* However, the digitization information may be recorded in one of three */ /* different tables, since the hit could have occurred in a wire chamber, */ /* a hodoscope, or the calorimeter. The naming of the relationship via the */ /* BY keyword is essential here. Without that, what would ADAMO call */ /* the new linking variable? mcHit_dataPuls? mcHit_dataHodo? */ /* mcHit_dataCalo? It's ambigous. When you specify several destination */ /* tables for your link, using the Boolean OR ('|') operator, you are */ /* creating a GENERALIZED relationship, and MUST give it a name. */ /* TWO fortran variables will be created by this generalized relationship: */ /* mcHit_digiTable (containing the name of the target table) and */ /* mcHit_digiTable_ (containing the target row number within that table). */ /* We're finished with relationship definitions. */ END RSET /* ------------------------------------------------------------------------ */ /* GROUP TABLES INTO DATAFLOWS */ /* ------------------------------------------------------------------------ */ /* Dataflows are another logical uber-grouping of information. They are */ /* important because ADAMO programs typically read information from GAF's */ /* and write information to GAF's one dataflow at a time. This is much more */ /* convenient than having to explicitly read and write each table */ /* separately. Thus, be sure you include all the tables of ultimate */ /* interest in some dataflow. It is perfectly OK to leave out tables that */ /* are of a temporary or administrative nature. */ DEFINE DATAFLOW mcEvData= {mcEvent},{mcBeam},{mcTrack},{mcVert},{mcHit}; mcEvDigits = {dataPuls}, {dataHodo}, {dataCalo}; mcEvents= mcEvData, mcEvDigits : 'full Monte Carlo event information'; END DATAFLOW END SUBSCHEMA