Author: [log in to unmask] Date: Wed Jan 6 08:21:16 2016 New Revision: 4091 Log: actually add the stuff in my sandbox Added: java/sandbox/DatabaseConditionsManager.java java/sandbox/HPSTrack.java java/sandbox/MultipleScattering.java java/sandbox/SvtBiasConstant.java java/sandbox/SvtOldHeaderAnalysisDriver.java java/sandbox/SvtOldHeaderDataInfo.java java/sandbox/TrackUtils.java Added: java/sandbox/DatabaseConditionsManager.java ============================================================================= --- java/sandbox/DatabaseConditionsManager.java (added) +++ java/sandbox/DatabaseConditionsManager.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,1134 @@ +package org.hps.conditions.database; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.hps.conditions.api.AbstractConditionsObjectConverter; +import org.hps.conditions.api.ConditionsObject; +import org.hps.conditions.api.ConditionsObjectCollection; +import org.hps.conditions.api.ConditionsObjectException; +import org.hps.conditions.api.ConditionsRecord; +import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection; +import org.hps.conditions.api.ConditionsSeries; +import org.hps.conditions.api.TableMetaData; +import org.hps.conditions.api.TableRegistry; +import org.hps.conditions.ecal.EcalConditions; +import org.hps.conditions.ecal.EcalConditionsConverter; +import org.hps.conditions.ecal.TestRunEcalConditionsConverter; +import org.hps.conditions.svt.SvtConditions; +import org.hps.conditions.svt.SvtConditionsConverter; +import org.hps.conditions.svt.SvtDetectorSetup; +import org.hps.conditions.svt.TestRunSvtConditionsConverter; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; +import org.lcsim.conditions.ConditionsConverter; +import org.lcsim.conditions.ConditionsManager; +import org.lcsim.conditions.ConditionsManagerImplementation; +import org.lcsim.geometry.Detector; +import org.lcsim.geometry.Subdetector; +import org.lcsim.util.log.DefaultLogFormatter; +import org.lcsim.util.log.LogUtil; +import org.lcsim.util.loop.DetectorConditionsConverter; + +/** + * <p> + * This class provides the top-level API for accessing database conditions, as well as configuring the database + * connection, initializing all required components, and loading required converters and table meta data. It is + * registered as the global <code>ConditionsManager</code> in the constructor. + * <p> + * Differences between Test Run and Engineering Run configurations are handled automatically. + * + * @see org.lcsim.conditions.ConditionsManager + * @author Jeremy McCormick, SLAC + */ +@SuppressWarnings("rawtypes") +public final class DatabaseConditionsManager extends ConditionsManagerImplementation { + + /** + * Name of system property that can be used to specify custom database connection parameters. + */ + private static final String CONNECTION_PROPERTY = "org.hps.conditions.connection.file"; + + /** + * The default XML config. + */ + private static final String DEFAULT_CONFIG = "/org/hps/conditions/config/conditions_database_prod.xml"; + + /** + * The connection properties resource for connecting to the default JLAB database. + */ + private static final String DEFAULT_CONNECTION_PROPERTIES_RESOURCE = "/org/hps/conditions/config/jlab_dev_connection.prop"; + //private static final String DEFAULT_CONNECTION_PROPERTIES_RESOURCE = "/org/hps/conditions/config/jlab_connection.prop"; + + /** + * The Eng Run XML config. + */ + private static final String ENGRUN_CONFIG = "/org/hps/conditions/config/conditions_database_engrun.xml"; + + /** + * Initialize the logger. + */ + private static Logger logger = LogUtil.create(DatabaseConditionsManager.class.getName(), new DefaultLogFormatter(), + Level.FINE); + + /** + * The Test Run XML config. + */ + private static final String TEST_RUN_CONFIG = "/org/hps/conditions/config/conditions_database_testrun_2012.xml"; + + /** + * The max value for a run to be considered Test Run. + */ + private static final int TEST_RUN_MAX_RUN = 1365; + + static { + // Set default login timeout of 5 seconds. + DriverManager.setLoginTimeout(5); + } + + /** + * Get the static instance of this class. + * + * @return the static instance of the manager + */ + public static synchronized DatabaseConditionsManager getInstance() { + + // Is there no manager installed yet? + if (!ConditionsManager.isSetup() || !(ConditionsManager.defaultInstance() instanceof DatabaseConditionsManager)) { + logger.finest("creating new DatabaseConditionsManager instance"); + // Create a new instance if necessary, which will install it globally as the default. + new DatabaseConditionsManager(); + } + + // Get the instance back from the default conditions system and check that the type is correct now. + final ConditionsManager manager = ConditionsManager.defaultInstance(); + if (!(manager instanceof DatabaseConditionsManager)) { + logger.severe("default conditions manager has wrong type: " + manager.getClass()); + throw new RuntimeException("Default conditions manager has the wrong type: " + + ConditionsManager.defaultInstance().getClass().getName()); + } + + return (DatabaseConditionsManager) manager; + } + + /** + * Get the Logger for this class, which can be used by related sub-classes if they do not have their own logger. + * + * @return the Logger for this class + */ + public static Logger getLogger() { + return logger; + } + + /** + * Utility method to determine if a run number is from the 2012 Test Run. + * + * @param runNumber the run number + * @return <code>true</code> if run number is from the Test Run + */ + public static boolean isTestRun(final int runNumber) { + return runNumber > 0 && runNumber <= TEST_RUN_MAX_RUN; + } + + /** + * Reset the global static instance of the conditions manager to a new object. + */ + public static synchronized void resetInstance() { + logger.finest("DatabaseConditionsManager instance is being reset"); + new DatabaseConditionsManager(); + } + + /** + * True to cache all known conditions sets (from keys) during initialization. + */ + private boolean cacheAllConditions = false; + + /** + * True to close the connection after initialization. + */ + private boolean closeConnectionAfterInitialize = true; + + /** + * The current database connection. + */ + private Connection connection; + + /** + * The current connection parameters. + */ + private ConnectionParameters connectionParameters; + + /** + * The connection properties file, if one is being used from the command line. + */ + private File connectionPropertiesFile; + + /** + * Create the global registry of conditions object converters. + */ + private final ConverterRegistry converters = ConverterRegistry.create(); + + /** + * The converter for creating the combined ECAL conditions object. + */ + private ConditionsConverter ecalConverter; + + /** + * The default ECAL detector name in the detector geometry. + */ + private String ecalName = "Ecal"; + + /** + * True to freeze the system after initialization. + */ + private boolean freezeAfterInitialize = false; + + /** + * True if the conditions manager was configured from an XML configuration resource or file. + */ + private boolean isConfigured = false; + + /** + * True if manager is connected to the database. + */ + private boolean isConnected = false; + + /** + * True if the conditions system has been frozen and will ignore updates after it is initialized. + */ + private boolean isFrozen = false; + + /** + * True if the manager has been initialized, e.g. the {@link #setDetector(String, int)} method was called. + */ + private boolean isInitialized = false; + + /** + * True if current run number is from Test Run. + */ + private boolean isTestRun = false; + + /** + * Flag used to print connection parameters one time. + */ + private boolean loggedConnectionParameters = false; + + /** + * True to setup the SVT detector model with conditions. + */ + private boolean setupSvtDetector = true; + + /** + * The converter for creating the combined SVT conditions object. + */ + private ConditionsConverter svtConverter; + + /** + * The default SVT name in the detector geometry. + */ + private String svtName = "Tracker"; + + /** + * The helper for setting up the SVT detector with its conditions information. + */ + private final SvtDetectorSetup svtSetup = new SvtDetectorSetup(this.svtName); + + /** + * Create the global registry of table meta data. + */ + private final TableRegistry tableRegistry = TableRegistry.getTableRegistry(); + + /** + * The currently active conditions tag. + */ + private String tag = null; + + /** + * Class constructor. Calling this will automatically register this manager as the global default. + */ + private DatabaseConditionsManager() { + this.registerConditionsConverter(new DetectorConditionsConverter()); + this.setupConnectionFromSystemProperty(); + ConditionsManager.setDefaultConditionsManager(this); + this.setRun(-1); + for (final AbstractConditionsObjectConverter converter : this.converters.values()) { + // logger.fine("registering converter for " + converter.getType()); + this.registerConditionsConverter(converter); + } + this.addConditionsListener(this.svtSetup); + } + + /** + * Cache conditions sets for all known tables. + */ + private void cacheConditionsSets() { + for (final TableMetaData meta : this.tableRegistry.values()) { + try { + logger.fine("caching conditions " + meta.getKey() + " with type " + + meta.getCollectionClass().getCanonicalName()); + this.getCachedConditions(meta.getCollectionClass(), meta.getKey()); + } catch (final Exception e) { + logger.warning("could not cache conditions " + meta.getKey()); + } + } + } + + /** + * Close the database connection. + */ + public synchronized void closeConnection() { + logger.fine("closing connection"); + if (this.connection != null) { + try { + if (!this.connection.isClosed()) { + this.connection.close(); + } + } catch (final SQLException e) { + throw new RuntimeException(e); + } + } + this.connection = null; + this.isConnected = false; + logger.fine("connection closed"); + } + + /** + * Close the database connection but only if there was a connection opened based on the flag. Otherwise, it should + * be left open. Used in conjunction with return value of {@link #openConnection()}. + * + * @param connectionOpened <code>true</code> to close the connection; <code>false</code> to leave it open + */ + public synchronized void closeConnection(final boolean connectionOpened) { + if (connectionOpened) { + this.closeConnection(); + } + } + + /** + * This method will return <code>true</code> if the given collection ID already exists in the table. + * + * @param tableName the name of the table + * @param collectionID the collection ID value + * @return <code>true</code> if collection exists + */ + public boolean collectionExists(final String tableName, final int collectionID) { + final String sql = "SELECT * FROM " + tableName + " where collection_id = " + collectionID; + final ResultSet resultSet = this.selectQuery(sql); + try { + resultSet.last(); + } catch (final SQLException e) { + e.printStackTrace(); + } + int rowCount = 0; + try { + rowCount = resultSet.getRow(); + } catch (final SQLException e) { + e.printStackTrace(); + } + return rowCount != 0; + } + + /** + * Configure this class from an <code>InputStream</code> which should point to an XML document. + * + * @param in the InputStream which should be in XML format + */ + private void configure(final InputStream in) { + if (!this.isConfigured) { + final SAXBuilder builder = new SAXBuilder(); + Document config = null; + try { + config = builder.build(in); + } catch (JDOMException | IOException e) { + throw new RuntimeException(e); + } + this.loadConfiguration(config); + try { + in.close(); + } catch (final IOException e) { + logger.warning(e.getMessage()); + } + this.isConfigured = true; + } else { + logger.warning("System is already configured, so call to configure is ignored!"); + } + } + + /** + * Find a collection of conditions validity records by key name. The key name is distinct from the table name, but + * they are usually set to the same value. + * + * @param name the conditions key name + * @return the set of matching conditions records + */ + public ConditionsRecordCollection findConditionsRecords(final String name) { + final ConditionsRecordCollection runConditionsRecords = this.getCachedConditions( + ConditionsRecordCollection.class, "conditions").getCachedData(); + logger.fine("searching for conditions with name " + name + " in " + runConditionsRecords.size() + " records"); + final ConditionsRecordCollection foundConditionsRecords = new ConditionsRecordCollection(); + for (final ConditionsRecord record : runConditionsRecords) { + if (record.getName().equals(name)) { + if (this.matchesTag(record)) { + try { + foundConditionsRecords.add(record); + } catch (final ConditionsObjectException e) { + throw new RuntimeException(e); + } + logger.finer("found matching conditions record " + record.getRowId()); + } else { + logger.finer("conditions record " + record.getRowId() + " rejected from non-matching tag " + + record.getTag()); + } + } + } + logger.fine("found " + foundConditionsRecords.size() + " conditions records matching tag " + this.tag); + return foundConditionsRecords; + } + + /** + * Find table information from the collection type. + * + * @param type the collection type + * @return the table information or <code>null</code> if does not exist + */ + public List<TableMetaData> findTableMetaData(final Class<?> type) { + return this.tableRegistry.findByCollectionType(type); + } + + /** + * Find table information from the name. + * + * @param name the name of the table + * @return the table information or <code>null</code> if does not exist + */ + public TableMetaData findTableMetaData(final String name) { + return this.tableRegistry.findByTableName(name); + } + + /** + * This method can be called to "freeze" the conditions system so that any subsequent updates to run number or + * detector name will be ignored. + */ + public synchronized void freeze() { + if (this.getDetector() != null && this.getRun() != -1) { + this.isFrozen = true; + logger.config("conditions system is frozen"); + } else { + logger.warning("conditions system cannot be frozen because it is not initialized yet"); + } + } + + /** + * Add a row for a new collection and return the new collection ID assigned to it. + * + * @param tableName the name of the table + * @param comment an optional comment about this new collection + * @return the collection's ID + * @throws SQLException + */ + public synchronized int getCollectionId(final ConditionsObjectCollection<?> collection, final String description) + throws SQLException { + + final String caller = Thread.currentThread().getStackTrace()[2].getClassName(); + final String log = "created by " + System.getProperty("user.name") + " using " + + caller.substring(caller.lastIndexOf('.') + 1); + final boolean opened = this.openConnection(); + PreparedStatement statement = null; + ResultSet resultSet = null; + int collectionId = -1; + try { + statement = this.connection.prepareStatement( + "INSERT INTO collections (table_name, log, description, created) VALUES (?, ?, ?, NOW())", + Statement.RETURN_GENERATED_KEYS); + statement.setString(1, collection.getTableMetaData().getTableName()); + statement.setString(2, log); + if (description == null) { + statement.setNull(3, java.sql.Types.VARCHAR); + } else { + statement.setString(3, description); + } + statement.execute(); + resultSet = statement.getGeneratedKeys(); + resultSet.next(); + collectionId = resultSet.getInt(1); + } finally { + if (resultSet != null) { + resultSet.close(); + } + if (statement != null) { + statement.close(); + } + this.closeConnection(opened); + } + collection.setCollectionId(collectionId); + return collectionId; + } + + /** + * Get a list of all the {@link ConditionsRecord} objects. + * + * @return the list of all the {@link ConditionsRecord} objects + */ + // FIXME: This should use a cache that is created during initialization, rather than look these up every time. + public ConditionsRecordCollection getConditionsRecords() { + logger.finer("getting conditions records ..."); + final ConditionsRecordCollection conditionsRecords = new ConditionsRecordCollection(); + for (final TableMetaData tableMetaData : this.tableRegistry.values()) { + try { + final ConditionsRecordCollection foundConditionsRecords = this.findConditionsRecords(tableMetaData + .getKey()); + logger.finer("found " + foundConditionsRecords.size() + " collections with name " + + tableMetaData.getKey()); + conditionsRecords.addAll(foundConditionsRecords); + } catch (final Exception e) { + e.printStackTrace(); + logger.warning(e.getMessage()); + } + } + logger.finer("found " + conditionsRecords + " conditions records"); + logger.getHandlers()[0].flush(); + return conditionsRecords; + } + + /** + * Get a conditions series with one or more collections. + * + * @param collectionType the type of the collection + * @param tableName the name of the data table + * @param <ObjectType> the type of the conditions object + * @param <CollectionType> the type of the conditions collection + * @return the conditions series + */ + @SuppressWarnings("unchecked") + public <ObjectType extends ConditionsObject, CollectionType extends ConditionsObjectCollection<ObjectType>> ConditionsSeries<ObjectType, CollectionType> getConditionsSeries( + final Class<CollectionType> collectionType, final String tableName) { + + final TableMetaData metaData = this.tableRegistry.get(tableName); + if (metaData == null) { + throw new IllegalArgumentException("No table metadata found for type " + collectionType.getName()); + } + if (!metaData.getCollectionClass().equals(collectionType)) { + throw new IllegalArgumentException("The type " + collectionType.getName() + " does not match the class " + + metaData.getCollectionClass().getName() + " from the meta data"); + } + final Class<? extends ConditionsObject> objectType = metaData.getObjectClass(); + final ConditionsSeriesConverter<ObjectType, CollectionType> converter = new ConditionsSeriesConverter( + objectType, collectionType); + return converter.createSeries(tableName); + } + + /** + * Get the JDBC connection. + * + * @return the JDBC connection + */ + public Connection getConnection() { + if (!this.isConnected()) { + this.openConnection(); + } + return this.connection; + } + + /** + * Get the current LCSim compact <code>Detector</code> object with the geometry and detector model. + * + * @return the detector object + */ + public Detector getDetectorObject() { + return this.getCachedConditions(Detector.class, "compact.xml").getCachedData(); + } + + /** + * Get the combined ECAL conditions for this run. + * + * @return the combined ECAL conditions + */ + public EcalConditions getEcalConditions() { + return this.getCachedConditions(EcalConditions.class, "ecal_conditions").getCachedData(); + } + + /** + * Get the name of the ECAL in the detector geometry. + * + * @return the name of the ECAL + */ + public String getEcalName() { + return this.ecalName; + } + + /** + * Get the subdetector object of the ECAL. + * + * @return the ECAL subdetector + */ + public Subdetector getEcalSubdetector() { + return this.getDetectorObject().getSubdetector(this.ecalName); + } + + /** + * Get the combined SVT conditions for this run. + * + * @return the combined SVT conditions + */ + public SvtConditions getSvtConditions() { + return this.getCachedConditions(SvtConditions.class, "svt_conditions").getCachedData(); + } + + /** + * Get the set of available conditions tags from the conditions table + * + * @return the set of available conditions tags + */ + public Set<String> getTags() { + logger.fine("getting list of available conditions tags"); + final boolean openedConnection = this.openConnection(); + final Set<String> tags = new LinkedHashSet<String>(); + final ResultSet rs = this + .selectQuery("select distinct(tag) from conditions where tag is not null order by tag"); + try { + while (rs.next()) { + tags.add(rs.getString(1)); + } + } catch (final SQLException e) { + throw new RuntimeException(e); + } + try { + rs.close(); + } catch (final SQLException e) { + logger.log(Level.WARNING, "error closing ResultSet", e); + } + final StringBuffer sb = new StringBuffer(); + sb.append("found unique conditions tags: "); + for (final String tag : tags) { + sb.append(tag + " "); + } + sb.setLength(sb.length() - 1); + logger.fine(sb.toString()); + this.closeConnection(openedConnection); + return tags; + } + + /** + * True if there is a conditions record with the given name. + * + * @param name the conditions record name (usually will match to table name) + * @return <code>true</code> if a conditions record exists with the given name + */ + public boolean hasConditionsRecord(final String name) { + return this.findConditionsRecords(name).size() != 0; + } + + /** + * Perform all necessary initialization, including setup of the XML configuration and loading of conditions onto the + * Detector. This is called from the {@link #setDetector(String, int)} method to setup the manager for a new run or + * detector. + * + * @param detectorName the name of the detector model + * @param runNumber the run number + * @throws ConditionsNotFoundException if there is a conditions system error + */ + private void initialize(final String detectorName, final int runNumber) throws ConditionsNotFoundException { + + logger.config("initializing with detector " + detectorName + " and run " + runNumber); + + // Is not configured yet? + if (!this.isConfigured) { + if (isTestRun(runNumber)) { + // This looks like the Test Run so use the custom configuration for it. + this.setXmlConfig(DatabaseConditionsManager.TEST_RUN_CONFIG); + } else if (runNumber > TEST_RUN_MAX_RUN) { + // Run numbers greater than max of Test Run assumed to be Eng Run (for now!). + this.setXmlConfig(DatabaseConditionsManager.ENGRUN_CONFIG); + } else if (runNumber == 0) { + // Use the default configuration because the run number is basically meaningless. + this.setXmlConfig(DatabaseConditionsManager.DEFAULT_CONFIG); + } + } + + // Register the converters for this initialization. + logger.fine("registering converters"); + this.registerConverters(); + + // Enable or disable the setup of the SVT detector. + logger.fine("enabling SVT setup: " + this.setupSvtDetector); + this.svtSetup.setEnabled(this.setupSvtDetector); + + // Open the database connection. + this.openConnection(); + + // Call the super class's setDetector method to construct the detector object and activate conditions listeners. + logger.fine("activating default conditions manager"); + super.setDetector(detectorName, runNumber); + + // Should all conditions sets be cached? + if (this.cacheAllConditions) { + // Cache the conditions sets of all registered converters. + logger.fine("caching all conditions sets ..."); + this.cacheConditionsSets(); + } + + if (this.closeConnectionAfterInitialize) { + logger.fine("closing connection after initialization"); + // Close the connection. + this.closeConnection(); + } + + // Should the conditions system be frozen now? + if (this.freezeAfterInitialize) { + // Freeze the conditions system so subsequent updates will be ignored. + this.freeze(); + logger.config("system was frozen after initialization"); + } + + this.isInitialized = true; + + logger.info("conditions system initialized successfully"); + + // Flush logger after initialization. + logger.getHandlers()[0].flush(); + } + + /** + * Check if connected to the database. + * + * @return <code>true</code> if connected + */ + public boolean isConnected() { + return this.isConnected; + } + + /** + * True if conditions system is frozen + * + * @return <code>true</code> if conditions system is currently frozen + */ + public boolean isFrozen() { + return this.isFrozen; + } + + /** + * True if conditions manager is properly initialized. + * + * @return <code>true</code> if the manager is initialized + */ + public boolean isInitialized() { + return this.isInitialized; + } + + /** + * Return <code>true</code> if Test Run configuration is active + * + * @return <code>true</code> if Test Run configuration is active + */ + public boolean isTestRun() { + return this.isTestRun; + } + + /** + * Load configuration information from an XML document. + * + * @param document the XML document + */ + private void loadConfiguration(final Document document) { + + final Element node = document.getRootElement().getChild("configuration"); + + if (node == null) { + return; + } + + Element element = node.getChild("setupSvtDetector"); + if (element != null) { + this.setupSvtDetector = Boolean.parseBoolean(element.getText()); + logger.config("setupSvtDetector = " + this.setupSvtDetector); + } + + element = node.getChild("ecalName"); + if (element != null) { + this.setEcalName(element.getText()); + } + + element = node.getChild("svtName"); + if (element != null) { + this.setSvtName(element.getText()); + } + + element = node.getChild("freezeAfterInitialize"); + if (element != null) { + this.freezeAfterInitialize = Boolean.parseBoolean(element.getText()); + logger.config("freezeAfterInitialize = " + this.freezeAfterInitialize); + } + + element = node.getChild("cacheAllCondition"); + if (element != null) { + this.cacheAllConditions = Boolean.parseBoolean(element.getText()); + logger.config("cacheAllConditions = " + this.cacheAllConditions); + } + + element = node.getChild("isTestRun"); + if (element != null) { + this.isTestRun = Boolean.parseBoolean(element.getText()); + logger.config("isTestRun = " + this.isTestRun); + } + + element = node.getChild("logLevel"); + if (element != null) { + this.setLogLevel(Level.parse(element.getText())); + } + + element = node.getChild("closeConnectionAfterInitialize"); + if (element != null) { + this.closeConnectionAfterInitialize = Boolean.parseBoolean(element.getText()); + logger.config("closeConnectionAfterInitialize = " + this.closeConnectionAfterInitialize); + } + + element = node.getChild("loginTimeout"); + if (element != null) { + final Integer timeout = Integer.parseInt(element.getText()); + DriverManager.setLoginTimeout(timeout); + logger.config("loginTimeout = " + timeout); + } + } + + /** + * Return <code>true</code> if the conditions record matches the current tag + * + * @param record the conditions record + * @return <code>true</code> if conditions record matches the currently used tag + */ + private boolean matchesTag(final ConditionsRecord record) { + if (this.tag == null) { + // If there is no tag set then all records pass. + return true; + } + final String recordTag = record.getTag(); + if (recordTag == null) { + // If there is a tag set but the record has no tag, it is rejected. + return false; + } + return this.tag.equals(recordTag); + } + + public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection( + final Class<CollectionType> collectionType) { + final List<TableMetaData> tableMetaDataList = TableRegistry.getTableRegistry().findByCollectionType( + collectionType); + if (tableMetaDataList.size() > 1) { + throw new RuntimeException("More than one table meta data object returned for type: " + + collectionType.getName()); + } + final TableMetaData tableMetaData = tableMetaDataList.get(0); + CollectionType collection; + try { + collection = collectionType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("Error creating new collection.", e); + } + collection.setTableMetaData(tableMetaData); + collection.setConnection(this.getConnection()); + return collection; + } + + public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection( + final Class<CollectionType> collectionType, final String tableName) { + final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName(tableName); + CollectionType collection; + try { + collection = collectionType.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("Error creating new collection.", e); + } + collection.setTableMetaData(tableMetaData); + collection.setConnection(this.getConnection()); + return collection; + } + + /** + * Open the database connection. + * + * @return <code>true</code> if a connection was opened; <code>false</code> if using an existing connection. + */ + public synchronized boolean openConnection() { + boolean openedConnection = false; + if (!this.isConnected) { + // Do the connection parameters need to be figured out automatically? + if (this.connectionParameters == null) { + // Setup the default read-only connection, which will choose a SLAC or JLab database. + this.connectionParameters = ConnectionParameters.fromResource(DEFAULT_CONNECTION_PROPERTIES_RESOURCE); + } + + if (!this.loggedConnectionParameters) { + // Print out detailed info to the log on first connection within the job. + logger.info("opening connection ... " + '\n' + "connection: " + + this.connectionParameters.getConnectionString() + '\n' + "host: " + + this.connectionParameters.getHostname() + '\n' + "port: " + + this.connectionParameters.getPort() + '\n' + "user: " + this.connectionParameters.getUser() + + '\n' + "database: " + this.connectionParameters.getDatabase()); + this.loggedConnectionParameters = true; + } + + // Create the connection using the parameters. + this.connection = this.connectionParameters.createConnection(); + this.isConnected = true; + openedConnection = true; + } + logger.fine("connection opened successfully"); + + // Flag to indicate whether an existing connection was used or not. + return openedConnection; + } + + /** + * Register the conditions converters with the manager. + */ + private void registerConverters() { + if (this.svtConverter != null) { + // Remove old SVT converter. + this.removeConditionsConverter(this.svtConverter); + } + + if (this.ecalConverter != null) { + // Remove old ECAL converter. + this.registerConditionsConverter(this.ecalConverter); + } + + // Is configured for TestRun? + if (this.isTestRun()) { + // Load Test Run specific converters. + this.svtConverter = new TestRunSvtConditionsConverter(); + this.ecalConverter = new TestRunEcalConditionsConverter(); + logger.config("registering Test Run conditions converters"); + } else { + // Load the default converters. + this.svtConverter = new SvtConditionsConverter(); + this.ecalConverter = new EcalConditionsConverter(); + logger.config("registering default conditions converters"); + } + this.registerConditionsConverter(this.svtConverter); + this.registerConditionsConverter(this.ecalConverter); + } + + /** + * This method can be used to perform a database SELECT query. + * + * @param query the SQL query string + * @return the <code>ResultSet</code> from the query + * @throws RuntimeException if there is a query error + */ + ResultSet selectQuery(final String query) { + logger.fine("executing SQL select query ..." + '\n' + query); + ResultSet result = null; + Statement statement = null; + try { + statement = this.connection.createStatement(); + result = statement.executeQuery(query); + } catch (final SQLException x) { + throw new RuntimeException("Error in query: " + query, x); + } + return result; + } + + /** + * Set the connection parameters of the conditions database. + * + * @param connectionParameters the connection parameters + */ + public void setConnectionParameters(final ConnectionParameters connectionParameters) { + this.connectionParameters = connectionParameters; + } + + /** + * Set the path to a properties file containing connection settings. + * + * @param file the properties file + */ + public void setConnectionProperties(final File file) { + logger.config("setting connection properties file " + file.getPath()); + if (!file.exists()) { + throw new IllegalArgumentException("The connection properties file does not exist: " + + this.connectionPropertiesFile.getPath()); + } + this.connectionParameters = ConnectionParameters.fromProperties(file); + } + + /** + * Set the connection parameters from an embedded resource location. + * + * @param resource the classpath resource location + */ + public void setConnectionResource(final String resource) { + logger.config("setting connection resource " + resource); + this.connectionParameters = ConnectionParameters.fromResource(resource); + } + + /** + * This method handles changes to the detector name and run number. It is called every time an LCSim event is + * created, and so it has internal logic to figure out if the conditions system actually needs to be updated. + */ + @Override + public synchronized void setDetector(final String detectorName, final int runNumber) + throws ConditionsNotFoundException { + + logger.finest("setDetector " + detectorName + " with run number " + runNumber); + + if (detectorName == null) { + throw new IllegalArgumentException("The detectorName argument is null."); + } + + if (!this.isInitialized || !detectorName.equals(this.getDetector()) || runNumber != this.getRun()) { + if (!this.isFrozen) { + logger.info("new detector " + detectorName + " and run #" + runNumber); + this.initialize(detectorName, runNumber); + } else { + logger.finest("Conditions changed but will be ignored because manager is frozen."); + } + } + } + + /** + * Set the name of the ECAL sub-detector. + * + * @param ecalName the name of the ECAL subdetector + */ + private void setEcalName(final String ecalName) { + if (ecalName == null) { + throw new IllegalArgumentException("The ecalName is null"); + } + this.ecalName = ecalName; + logger.info("ECAL name set to " + ecalName); + } + + /** + * Set the log level. + * + * @param level the new log level + */ + public void setLogLevel(final Level level) { + logger.config("setting log level to " + level); + logger.setLevel(level); + logger.getHandlers()[0].setLevel(level); + this.svtSetup.setLogLevel(level); + } + + /** + * Set the name of the SVT subdetector. + * + * @param svtName the name of the SVT subdetector + */ + private void setSvtName(final String svtName) { + if (svtName == null) { + throw new IllegalArgumentException("The svtName is null"); + } + this.svtName = svtName; + logger.info("SVT name set to " + this.ecalName); + } + + /** + * Set a tag used to filter the accessible conditions records + * + * @param tag the tag value used to filter returned conditions records + */ + public void setTag(final String tag) { + this.tag = tag; + logger.info("using conditions tag: " + tag); + } + + /** + * Setup the database connection from a file specified by a Java system property setting. This could be overridden + * by subsequent API calls to {@link #setConnectionProperties(File)} or {@link #setConnectionResource(String)}. + */ + private void setupConnectionFromSystemProperty() { + final String systemPropertiesConnectionPath = (String) System.getProperties().get(CONNECTION_PROPERTY); + if (systemPropertiesConnectionPath != null) { + final File f = new File(systemPropertiesConnectionPath); + if (!f.exists()) { + throw new RuntimeException("Connection properties file from " + CONNECTION_PROPERTY + + " does not exist."); + } + this.setConnectionProperties(f); + logger.info("connection setup from system property " + CONNECTION_PROPERTY + " = " + + systemPropertiesConnectionPath); + } + } + + /** + * Configure some properties of this object from an XML file + * + * @param file the XML file + */ + public void setXmlConfig(final File file) { + logger.config("setting XML config from file " + file.getPath()); + if (!file.exists()) { + throw new IllegalArgumentException("The config file does not exist: " + file.getPath()); + } + try { + this.configure(new FileInputStream(file)); + } catch (final FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Configure this object from an embedded XML resource. + * + * @param resource the embedded XML resource + */ + public void setXmlConfig(final String resource) { + logger.config("setting XML config from resource " + resource); + final InputStream is = this.getClass().getResourceAsStream(resource); + this.configure(is); + } + + /** + * Un-freeze the conditions system so that updates will be received again. + */ + public synchronized void unfreeze() { + this.isFrozen = false; + logger.info("conditions system unfrozen"); + } + + /** + * Perform a SQL query with an update command like INSERT, DELETE or UPDATE. + * + * @param query the SQL query string + * @return the keys of the rows affected + */ + public List<Integer> updateQuery(final String query) { + final boolean openedConnection = this.openConnection(); + logger.fine("executing SQL update query ..." + '\n' + query); + final List<Integer> keys = new ArrayList<Integer>(); + Statement statement = null; + ResultSet resultSet = null; + try { + statement = this.connection.createStatement(); + statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS); + resultSet = statement.getGeneratedKeys(); + while (resultSet.next()) { + final int key = resultSet.getInt(1); + keys.add(key); + } + } catch (final SQLException x) { + throw new RuntimeException("Error in SQL query: " + query, x); + } + DatabaseUtilities.cleanup(resultSet); + this.closeConnection(openedConnection); + return keys; + } +} Added: java/sandbox/HPSTrack.java ============================================================================= --- java/sandbox/HPSTrack.java (added) +++ java/sandbox/HPSTrack.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,393 @@ +package org.hps.recon.tracking; + +import static org.lcsim.constants.Constants.fieldConversion; +import hep.physics.matrix.SymmetricMatrix; +import hep.physics.vec.BasicHep3Vector; +import hep.physics.vec.Hep3Vector; +import hep.physics.vec.VecOp; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hps.util.Pair; +import org.lcsim.event.MCParticle; +import org.lcsim.fit.helicaltrack.HelicalTrackFit; +import org.lcsim.fit.helicaltrack.HelicalTrackHit; +import org.lcsim.fit.helicaltrack.HelixUtils; +import org.lcsim.fit.helicaltrack.MultipleScatter; +import org.lcsim.geometry.FieldMap; +import org.lcsim.spacegeom.CartesianVector; +import org.lcsim.spacegeom.SpacePoint; +import org.lcsim.spacegeom.SpaceVector; +import org.lcsim.util.swim.Helix; +import org.lcsim.util.swim.Line; +import org.lcsim.util.swim.Trajectory; + +/** + * Extension of HelicalTrackFit to include HPS-specific information and utilities. + * + * @author mgraham <[log in to unmask]> + * @author phansson <[log in to unmask]> + * + */ + +public class HPSTrack extends HelicalTrackFit { + + private BeamSpot _beam; + // all of the variables defined below are in the jlab (detector) frame + // this position & momentum are measured at the DOCA to the Y-axis, + // which is where the tracking returns it's parameters by default + private Hep3Vector _pDocaY; + private Hep3Vector _posDocaY; + // the position & momentum of the track at the intersection of the target (z=0) + private Hep3Vector _pTarget; + private Hep3Vector _posTarget; + // the position & momentum of the track at DOCA to the beam axis (z) + private Hep3Vector _pDocaZ; + private Hep3Vector _posDocaZ; + private double bField = 0.491; // make this set-able + private boolean _debug = false; + private boolean _debugForward = false; + private Trajectory _trajectory; + Map<Pair<Integer, Integer>, Double> _fieldMap; + Map<Pair<Integer, Integer>, Pair<Double, Double>> _fieldBins; + private MCParticle mcParticle; + + public HPSTrack(double[] pars, SymmetricMatrix cov, double[] chisq, int[] ndf, Map<HelicalTrackHit, Double> smap, Map<HelicalTrackHit, MultipleScatter> msmap, BeamSpot beam) { + super(pars, cov, chisq, ndf, smap, msmap); + _beam = beam; + calculateParametersAtTarget(); + calculateParametersAtDocaY(); + calculateParametersAtDocaZ(); + } + + public HPSTrack(double[] pars, SymmetricMatrix cov, double[] chisq, int[] ndf, Map<HelicalTrackHit, Double> smap, Map<HelicalTrackHit, MultipleScatter> msmap) { + super(pars, cov, chisq, ndf, smap, msmap); + calculateParametersAtTarget(); + calculateParametersAtDocaY(); + calculateParametersAtDocaZ(); + } + + public HPSTrack(HelicalTrackFit htf, BeamSpot beam) { + super(htf.parameters(), htf.covariance(), htf.chisq(), htf.ndf(), htf.PathMap(), htf.ScatterMap()); + _beam = beam; + calculateParametersAtTarget(); + calculateParametersAtDocaY(); + calculateParametersAtDocaZ(); + } + + public HPSTrack(HelicalTrackFit htf) { + super(htf.parameters(), htf.covariance(), htf.chisq(), htf.ndf(), htf.PathMap(), htf.ScatterMap()); + calculateParametersAtTarget(); + calculateParametersAtDocaY(); + calculateParametersAtDocaZ(); + } + + public HPSTrack(double[] parameters, SymmetricMatrix covariance, double[] chiSquared, int[] ndf, Map<HelicalTrackHit, Double> sMap, Map<HelicalTrackHit, MultipleScatter> msMap, MCParticle mcParticle) { + super(parameters, covariance, chiSquared, ndf, sMap, msMap); + + // Set the MC particle associated with this fit + this.mcParticle = mcParticle; + } + + /** + * Get map of the the track trajectory within the uniform bfield + */ + public Map<Integer, Double[]> trackTrajectory(double zStart, double zStop, int nSteps) { + Map<Integer, Double[]> traj = new HashMap<Integer, Double[]>(); + double step = (zStop - zStart) / nSteps; + Double zVal = zStart; + Integer nstep = 0; + while (zVal < zStop) { + Double[] xyz = {0.0, 0.0, 0.0}; + double s = HelixUtils.PathToXPlane(this, zVal, 1000.0, 1).get(0); + xyz[0] = HelixUtils.PointOnHelix(this, s).y(); + xyz[1] = HelixUtils.PointOnHelix(this, s).z(); + xyz[2] = zVal; + traj.put(nstep, xyz); + zVal += step; + nstep++; + } + return traj; + } + + /** + * Get map of the the track direction within the uniform bfield + */ + public Map<Integer, Double[]> trackDirection(double zStart, double zStop, int nSteps) { + Map<Integer, Double[]> traj = new HashMap<Integer, Double[]>(); + double step = (zStop - zStart) / nSteps; + Double zVal = zStart; + + Integer nstep = 0; + while (zVal < zStop) { + Double[] xyz = {0.0, 0.0, 0.0}; + double s = HelixUtils.PathToXPlane(this, zVal, 1000.0, 1).get(0); + xyz[0] = HelixUtils.Direction(this, s).y(); + xyz[1] = HelixUtils.Direction(this, s).z(); + xyz[2] = zVal; + traj.put(nstep, xyz); + zVal += step; + nstep++; + } + return traj; + } + + private void calculateParametersAtTarget() { + double pTot = this.p(bField); + // currently, PathToXPlane only returns a single path (no loopers!) + List<Double> paths = HelixUtils.PathToXPlane(this, 0.0, 100.0, 1); + Hep3Vector posTargetTrkSystem = HelixUtils.PointOnHelix(this, paths.get(0)); + Hep3Vector dirTargetTrkSystem = HelixUtils.Direction(this, paths.get(0)); + _posTarget = CoordinateTransformations.transformVectorToDetector(posTargetTrkSystem); + _pTarget = VecOp.mult(pTot, CoordinateTransformations.transformVectorToDetector(dirTargetTrkSystem)); + + } + + private void calculateParametersAtDocaY() { + double pTot = this.p(bField); + Hep3Vector posDocaYTrkSystem = HelixUtils.PointOnHelix(this, 0); + Hep3Vector dirDocaYTrkSystem = HelixUtils.Direction(this, 0); + _posDocaY = CoordinateTransformations.transformVectorToDetector(posDocaYTrkSystem); + _pDocaY = VecOp.mult(pTot, CoordinateTransformations.transformVectorToDetector(dirDocaYTrkSystem)); + + } + + private void calculateParametersAtDocaZ() { + double pTot = this.p(bField); + double sAtDocaZ = findPathToDocaZ(); + Hep3Vector posDocaZTrkSystem = HelixUtils.PointOnHelix(this, sAtDocaZ); + Hep3Vector dirDocaZTrkSystem = HelixUtils.Direction(this, sAtDocaZ); + _posDocaZ = CoordinateTransformations.transformVectorToDetector(posDocaZTrkSystem); + _pDocaZ = VecOp.mult(pTot, CoordinateTransformations.transformVectorToDetector(dirDocaZTrkSystem)); + } + + public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step) { + System.out.println("Don't use this anymore! Use the contructor with FieldMap provided"); + Hep3Vector out= new BasicHep3Vector(666,666,666); + Hep3Vector[] ret={out}; + return ret; + } + + + public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step, boolean debugOK) { + System.out.println("Don't use this anymore! Use the contructor with FieldMap provided"); + Hep3Vector out= new BasicHep3Vector(666,666,666); + Hep3Vector[] ret={out}; + return ret; + } + + /** + * Get the position and direction on the track using B-field map for + * extrapolation + * + * @param start = starting z-position of extrapolation + * @param zFinal = final z-position + * @param step = step size + * @param bmap = the B-Field map + * @return position[0] and direction[1] at Z=zfinal + */ + public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step, FieldMap bmap) { + return this.getPositionAtZMap(start, xFinal, step, bmap, false); + } + + public Hep3Vector[] getPositionAtZMap(double start, double xFinal, double step, FieldMap bmap, boolean debugOk) { + + double startFringe = start; + + _debugForward = false; + if (xFinal > 900) + _debugForward = debugOk ? true : false; + // if looking upstream, we'll be propagating backwards + if (xFinal < 0) + step = -step; + if (_debugForward) + System.out.println(this.toString()); + + double sStartFringe = HelixUtils.PathToXPlane(this, startFringe, 1000.0, 1).get(0); + if (_debugForward) + System.out.println("path to end of fringe = " + sStartFringe + "; xFinal = " + xFinal); + double xtmp = startFringe; + double ytmp = HelixUtils.PointOnHelix(this, sStartFringe).y(); + double ztmp = HelixUtils.PointOnHelix(this, sStartFringe).z(); + double Rorig = this.R(); + double xCtmp = this.xc(); + double yCtmp = this.yc(); + double q = Math.signum(this.curvature()); + double phitmp = getPhi(xtmp, ytmp, xCtmp, yCtmp, q); + if (_debugForward) { + System.out.println("\nOriginal xtmp = " + xtmp + "; ytmp = " + ytmp + "; ztmp = " + ztmp + "; phitmp = " + phitmp); + + System.out.println("nOriginal Rorig = " + Rorig + "; xCtmp = " + xCtmp + "; yCtmp = " + yCtmp); + } + if (_debugForward) + System.out.println("Original Direction at Fringe: " + HelixUtils.Direction(this, startFringe).toString()); + double Rtmp = Rorig; + // now start stepping through the fringe field + Hep3Vector r0Tmp = HelixUtils.PointOnHelix(this, sStartFringe); + SpacePoint r0 = new SpacePoint(r0Tmp); + double pTot = this.p(bField); + Hep3Vector dirOrig = HelixUtils.Direction(this, sStartFringe); + Hep3Vector p0 = VecOp.mult(pTot, dirOrig); + Hep3Vector dirTmp = dirOrig; + SpacePoint rTmp = r0; + Hep3Vector pTmp = p0; + double pXOrig = p0.x(); + double pXTmp = pXOrig; + double totalS = sStartFringe; + if (_debugForward) { + double tmpdX = xFinal - startFringe; + Hep3Vector fooExt = extrapolateStraight(dirOrig, tmpdX); + Hep3Vector fooFinal = VecOp.add(fooExt, r0Tmp); + System.out.println("Extrpolating straight back from startFringe = (" + fooFinal.x() + "," + fooFinal.y() + "," + fooFinal.z() + ")"); + + } + // follow trajectory while: in fringe field, before end point, and we don't have a looper + while (Math.signum(step) * xtmp < Math.signum(step) * xFinal && Math.signum(pXOrig * pXTmp) > 0) { + if (_debugForward) { + System.out.println("New step in Fringe Field"); + System.out.println("rTmp = " + rTmp.toString()); + System.out.println("pTmp = " + pTmp.toString()); + System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(this, totalS)); + System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(this, totalS))); + } + + double myBField = bmap.getField(new BasicHep3Vector(rTmp.z(), rTmp.z(), rTmp.x())).z(); // note weird co ordinates for track vs det + if (_debugForward) + System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField); + setTrack(pTmp, rTmp, q, myBField); + rTmp = _trajectory.getPointAtDistance(step); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + xtmp = rTmp.x(); + if (_debugForward) { + System.out.println("############## done... #############"); + + System.out.println("\n"); + } + totalS += step; + } + + // Go with finer granularity in the end + rTmp = _trajectory.getPointAtDistance(0); + xtmp = rTmp.x(); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + step = step / 10.0; + + while (Math.signum(step) * xtmp < Math.signum(step) * xFinal && Math.signum(pXOrig * pXTmp) > 0) { + if (_debugForward) { + System.out.println("New step in Fringe Field"); + System.out.println("rTmp = " + rTmp.toString()); + System.out.println("pTmp = " + pTmp.toString()); + System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(this, totalS)); + System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(this, totalS))); + } + + double myBField = bmap.getField(new BasicHep3Vector(rTmp.z(), rTmp.z(), rTmp.x())).z(); // note weird co ordinates for track vs det + + if (_debugForward) + System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField); + setTrack(pTmp, rTmp, q, myBField); + rTmp = _trajectory.getPointAtDistance(step); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + xtmp = rTmp.x(); + if (_debugForward) { + System.out.println("############## done... #############"); + System.out.println("\n"); + } + totalS += step; + } + + // ok, done with field. + Hep3Vector pointInTrking = new BasicHep3Vector(rTmp.x(), rTmp.y(), rTmp.z()); + if (_debugForward) + System.out.println("Position xfinal (tracking) : x = " + xFinal + "; y = " + pointInTrking.y() + "; z = " + pointInTrking.z()); + Hep3Vector[] out = {CoordinateTransformations.transformVectorToDetector(pointInTrking), CoordinateTransformations.transformVectorToDetector(pTmp)}; + + return out; + } + + private double getPhi(double x, double y, double xc, double yc, double sign) { + // System.out.println("Math.atan2(y - yc, x - xc)="+Math.atan2(y - yc, x - xc)); + return Math.atan2(y - yc, x - xc) - sign * Math.PI / 2; + } + + private Hep3Vector extrapolateStraight(Hep3Vector dir, double deltaX) { + double deltaY = deltaX * dir.y(); + double deltaZ = deltaX * dir.z(); + return new BasicHep3Vector(deltaX, deltaY, deltaZ); + } + + // field that changes linearly from Bmax->0 + private double getFringe(double x, double halfWidth) { + // System.out.println("x = " + x + "; halfWidth = " + halfWidth); + if (x / halfWidth > 1) + return 1; + if (x / halfWidth < -1) + return 0; + + return (1.0 / 2.0) * (1 + x / halfWidth); + } + + private Hep3Vector getDirection(double phi, double sign) { + double ux = Math.cos(phi) * this.sth(); + double uy = Math.sin(phi) * this.sth(); + double uz = this.cth(); + // Return the direction unit vector + return new BasicHep3Vector(ux, uy, uz); + } + + private double findPathToDocaZ() { + double step = 0.1;// 100 um step size + double maxS = 100.0; // go to 10cm + double s = -30; + double minDist = 999999; + double minS = s; + double dist = 999998; + // once the distance starts increasing, quit and return + while (dist < minDist) { + Hep3Vector pos = HelixUtils.PointOnHelix(this, s); + dist = pos.y() * pos.y() + pos.z() * pos.z(); + s += step; + } + return minS; + } + + private void setTrack(Hep3Vector p0, SpacePoint r0, double q, double B) { + SpaceVector p = new CartesianVector(p0.v()); + double phi = Math.atan2(p.y(), p.x()); + double lambda = Math.atan2(p.z(), p.rxy()); + double field = B * fieldConversion; + + if (q != 0 && field != 0) { + double radius = p.rxy() / (q * field); + _trajectory = new Helix(r0, radius, phi, lambda); + } else + _trajectory = new Line(r0, phi, lambda); + } + + public Trajectory getTrajectory() { + return this._trajectory; + } + + /** + * Get the MC Particle associated with the HelicalTrackFit + * + * @return mcParticle : + */ + public MCParticle getMCParticle() { + return this.mcParticle; + } + + /** + * Set the MC Particle associated with the HelicalTrackFit + * + * @param mcParticle : + */ + public void setMCParticle(MCParticle mcParticle) { + this.mcParticle = mcParticle; + } +} Added: java/sandbox/MultipleScattering.java ============================================================================= --- java/sandbox/MultipleScattering.java (added) +++ java/sandbox/MultipleScattering.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,471 @@ +package org.hps.recon.tracking; + +import hep.physics.vec.Hep3Vector; +import hep.physics.vec.VecOp; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume; +import org.hps.recon.tracking.MaterialSupervisor.SiStripPlane; +import org.lcsim.detector.IDetectorElement; +import org.lcsim.detector.solids.Inside; +import org.lcsim.fit.helicaltrack.HelicalTrackFit; +import org.lcsim.fit.helicaltrack.HelixUtils; +import org.lcsim.recon.tracking.seedtracker.ScatterAngle; + +/** + * Extention of lcsim class to allow use of local classes. Finds scatter points + * and magnitude from detector geometry directly. + * + * @author Per Hansson <[log in to unmask]> + */ +public class MultipleScattering extends org.lcsim.recon.tracking.seedtracker.MultipleScattering { + + private boolean _fixTrackMomentum = false; + private double _momentum = -99;//dummy + private static final double inside_tolerance = 1.0;//tolerance for first (approximate) test of track intersection with sensor + + public MultipleScattering(MaterialManager materialmanager) { + super(materialmanager); + } + + /** + * Override lcsim version and select material manager depending on object + * type. This allows to use a local extension of the material manager in the + * lcsim track fitting code. + * + * @param helix + * @return a list of ScatterAngle. + */ + @Override + public List<ScatterAngle> FindScatters(HelicalTrackFit helix) { + if (_debug) { + System.out.printf("\n%s: FindScatters() for helix:\n%s\n", this.getClass().getSimpleName(), helix.toString()); + } + + if (MaterialSupervisor.class.isInstance(this._materialmanager)) { + if (_debug) { + System.out.printf("%s: use HPS scattering model", this.getClass().getSimpleName()); + } + return this.FindHPSScatters(helix); + } else { + if (_debug) { + System.out.printf("%s: use default lcsim material manager to find scatters\n", this.getClass().getSimpleName()); + } + return super.FindScatters(helix); + } + } + + /** + * Extra interface to keep a function returning the same type as the lcsim + * version + * + * @param helix + * @return a list of ScatterAngle. + */ + private List<ScatterAngle> FindHPSScatters(HelicalTrackFit helix) { + ScatterPoints scatterPoints = this.FindHPSScatterPoints(helix); + return scatterPoints.getScatterAngleList(); + } + + /** + * Find scatter points along helix using the local material manager + * + * @param helix + * @return the points of scatter along the helix + */ + public ScatterPoints FindHPSScatterPoints(HelicalTrackFit helix) { + if (_debug) { + System.out.printf("\n%s: FindHPSScatters() for helix:\n%s\n", this.getClass().getSimpleName(), helix.toString()); + System.out.printf("%s: momentum is p=%f,R=%f,B=%f \n", this.getClass().getSimpleName(), helix.p(Math.abs(_bfield)), helix.R(), _bfield); + } +// MG TURN THIS OFF SO IT DOESN'T ABORT STRAIGHT TRACKS + // Check that B Field is set + if (_bfield == 0. && !_fixTrackMomentum) { + throw new RuntimeException("B Field or fixed momentum must be set before calling FindScatters method"); + } + + // Create a new list to contain the mutliple scatters + // List<ScatterAngle> scatters = new ArrayList<ScatterAngle>(); + ScatterPoints scatters = new ScatterPoints(); + + MaterialSupervisor materialSupervisor = (MaterialSupervisor) this._materialmanager; + + List<ScatteringDetectorVolume> materialVols = materialSupervisor.getMaterialVolumes(); + + if (_debug) { + System.out.printf("%s: there are %d detector volumes in the model\n", this.getClass().getSimpleName(), materialVols.size()); + } + + for (ScatteringDetectorVolume vol : materialVols) { + + if (_debug) { + System.out.printf("\n%s: found detector volume \"%s\"\n", this.getClass().getSimpleName(), vol.getName()); + } + + // find intersection pathpoint with helix + Hep3Vector pos = getHelixIntersection(helix, vol); + + if (pos != null) { + + if (_debug) { + System.out.printf("%s: intersection position %s\n", this.getClass().getSimpleName(), pos.toString()); + } + + // find the track direction at the plane + double s = HelixUtils.PathToXPlane(helix, pos.x(), 0., 0).get(0); + + if (_debug) { + System.out.printf("%s: path length %f\n", this.getClass().getSimpleName(), s); + } + + Hep3Vector dir = HelixUtils.Direction(helix, s); + + if (_debug) { + System.out.printf("%s: track dir %s\n", this.getClass().getSimpleName(), dir.toString()); + } + + // Calculate the material the track will traverse + double radlen = vol.getMaterialTraversedInRL(dir); + + if (_debug) { + System.out.printf("%s: material traversed: %f R.L. (%fmm) \n", this.getClass().getSimpleName(), radlen, vol.getMaterialTraversed(dir)); + } + + double p; + if (_fixTrackMomentum) { + p = _momentum; + } else { + p = helix.p(this._bfield); + } + double msangle = this.msangle(p, radlen); + + ScatterAngle scat = new ScatterAngle(s, msangle); + + if (_debug) { + System.out.printf("%s: scatter angle %f rad for p %f GeV at path length %f\n", this.getClass().getSimpleName(), scat.Angle(), p, scat.PathLen()); + } + + ScatterPoint scatterPoint = new ScatterPoint(vol.getDetectorElement(), scat); + scatters.addPoint(scatterPoint); + + } else if (_debug) { + System.out.printf("\n%s: helix did not intersect this volume \n", this.getClass().getSimpleName()); + } + + } + + // Sort the multiple scatters by their path length + Collections.sort(scatters._points); + + if (_debug) { + System.out.printf("\n%s: found %d scatters for this helix:\n", this.getClass().getSimpleName(), scatters.getPoints().size()); + System.out.printf("%s: %10s %10s\n", this.getClass().getSimpleName(), "s (mm)", "theta(rad)"); + for (ScatterPoint p : scatters.getPoints()) { + System.out.printf("%s: %10.2f %10f\n", this.getClass().getSimpleName(), p.getScatterAngle().PathLen(), p.getScatterAngle().Angle()); + } + } + return scatters; + } + + public Hep3Vector getHelixIntersection(HelicalTrackFit helix, ScatteringDetectorVolume plane) { + + if (SiStripPlane.class.isInstance(plane)) { + return getHelixIntersection(helix, (SiStripPlane) plane); + } else { + throw new UnsupportedOperationException("This det volume type is not supported yet."); + } + } + + /* + * Returns interception between helix and plane Uses the origin x posiution of the plane and + * extrapolates linearly to find teh intersection If inside use an iterative "exact" way to + * determine the final position + */ + public Hep3Vector getHelixIntersection(HelicalTrackFit helix, SiStripPlane plane) { + + if (_debug) { + System.out.printf("%s: calculate simple helix intercept\n", this.getClass().getSimpleName()); + System.out.printf("%s: StripSensorPlane:\n", this.getClass().getSimpleName()); + plane.print(); + } + + double s_origin = HelixUtils.PathToXPlane(helix, plane.origin().x(), 0., 0).get(0); + + if (Double.isNaN(s_origin)) { + if (_debug) { + System.out.printf("%s: could not extrapolate to XPlane, too large curvature: origin is at %s \n", this.getClass().getSimpleName(), plane.origin().toString()); + } + return null; + } + + Hep3Vector pos = HelixUtils.PointOnHelix(helix, s_origin); + Hep3Vector direction = HelixUtils.Direction(helix, s_origin); + + if (_debug) { + System.out.printf("%s: position at x=origin is %s with path length %f and direction %s\n", this.getClass().getSimpleName(), pos.toString(), s_origin, direction.toString()); + } + + // Use this approximate position to get a first estimate if the helix intercepted the plane + // This is only because the real intercept position is an iterative procedure and we'd + // like to avoid using it if possible + // Consider the plane as pure x-plane i.e. no rotations + // -> this is not very general, as it assumes that strips are (mostly) along y -> FIX + // THIS!? + // Transformation from tracking to detector frame + Hep3Vector pos_det = VecOp.mult(VecOp.inverse(CoordinateTransformations.getMatrix()), pos); + Hep3Vector direction_det = VecOp.mult(VecOp.inverse(CoordinateTransformations.getMatrix()), direction); + + if (_debug) { + System.out.printf("%s: position in det frame %s and direction %s\n", this.getClass().getSimpleName(), pos_det.toString(), direction_det.toString()); + } + + // Transformation from detector frame to sensor frame + Hep3Vector pos_sensor = plane.getSensor().getGeometry().getGlobalToLocal().transformed(pos_det); + Hep3Vector direction_sensor = plane.getSensor().getGeometry().getGlobalToLocal().rotated(direction_det); + + if (_debug) { + System.out.printf("%s: position in sensor frame %s and direction %s\n", this.getClass().getSimpleName(), pos_sensor.toString(), direction_sensor.toString()); + } + + // find step in w to cross sensor plane + double delta_w = -1.0 * pos_sensor.z() / direction_sensor.z(); + + // find the point where it crossed the plane + Hep3Vector pos_int = VecOp.add(pos_sensor, VecOp.mult(delta_w, direction_sensor)); + Hep3Vector pos_int_det = plane.getSensor().getGeometry().getLocalToGlobal().transformed(pos_int); + // find the intercept in the tracking frame + Hep3Vector pos_int_trk = VecOp.mult(CoordinateTransformations.getMatrix(), pos_int_det); + + if (_debug) { + System.out.printf("%s: take step %f to get intercept position in sensor frame %s (det: %s trk: %s)\n", this.getClass().getSimpleName(), delta_w, pos_int, pos_int_det.toString(), pos_int_trk.toString()); + } + + boolean isInside = true; + if (Math.abs(pos_int.x()) > plane.getMeasuredDimension() / 2.0 + inside_tolerance) { + if (_debug) { + System.out.printf("%s: intercept is outside in u\n", this.getClass().getSimpleName()); + } + isInside = false; + } + + if (Math.abs(pos_int.y()) > plane.getUnmeasuredDimension() / 2.0 + inside_tolerance) { + if (_debug) { + System.out.printf("%s: intercept is outside in v\n", this.getClass().getSimpleName()); + } + isInside = false; + } + + // Check if it's inside sensor and module and if it contradicts the manual calculation + // For now: trust manual calculation and output warning if it's outside BOTH sensor AND module + if (_debug) { + // check if it's inside the sensor + Inside result_inside = plane.getDetectorElement().getGeometry().getPhysicalVolume().getMotherLogicalVolume().getSolid().inside(pos_int); + Inside result_inside_module = plane.getSensor().getGeometry().getDetectorElement().getParent().getGeometry().inside(pos_int_det); + System.out.printf("%s: Inside result sensor: %s module: %s\n", this.getClass().getSimpleName(), result_inside.toString(), result_inside_module.toString()); + + boolean isInsideSolid = false; + if (result_inside.equals(Inside.INSIDE) || result_inside.equals(Inside.SURFACE)) { + isInsideSolid = true; + } + + boolean isInsideSolidModule = false; + if (result_inside_module.equals(Inside.INSIDE) || result_inside_module.equals(Inside.SURFACE)) { + isInsideSolidModule = true; + } + + if (isInside && !isInsideSolid) { + System.out.printf("%s: manual calculation says inside sensor, inside solid says outside -> contradiction \n", this.getClass().getSimpleName()); + if (isInsideSolidModule) { + System.out.printf("%s: this intercept is outside sensor but inside module\n", this.getClass().getSimpleName()); + } else { + System.out.printf("%s: warning: this intercept at %s, in sensor frame %s, (sensor origin at %s ) is outside sensor and module!\n", this.getClass().getSimpleName(), pos_int_trk.toString(), pos_int.toString(), plane.origin().toString()); + } + } + } + + if (!isInside) { + return null; + } + + if (_debug) { + System.out.printf("%s: found simple intercept at %s \n", this.getClass().getSimpleName(), pos_int_trk.toString()); + } + + // TODO Catch special cases where the incidental iteration procedure seems to fail + if (Math.abs(helix.R()) < 2000 && Math.abs(helix.dca()) > 10.0) { + if (_debug) { + System.out.printf("%s: momentum is low (p=%f,R=%f,B=%f) and d0 is big (d0=%f), skip the iterative calculation\n", this.getClass().getSimpleName(), helix.p(Math.abs(_bfield)), helix.R(), _bfield, helix.dca()); + } + return pos_int_trk; + } + + if (_debug) { + System.out.printf("%s: calculate iterative helix intercept\n", this.getClass().getSimpleName()); + } + + //Hep3Vector pos_iter_trk = TrackUtils.getHelixPlaneIntercept(helix, plane.normal(), plane.origin(), _bfield, s_origin); + Hep3Vector pos_iter_trk = TrackUtils.getHelixPlaneIntercept(helix, plane.normal(), plane.origin(), _bfield); + + if (pos_iter_trk == null) { + System.out.printf("%s: iterative intercept failed for helix \n%s\n at sensor with org=%s, unit w=%s\n", this.getClass().getSimpleName(), helix.toString(), plane.origin().toString(), plane.normal().toString()); + System.out.printf("%s: => use simple intercept pos=%s\n", this.getClass().getSimpleName(), pos_int_trk); + System.out.printf("helix pos=%s dir=%s\n", pos, direction); + return pos_int_trk; + } + + if (_debug) { +// if (VecOp.sub(pos_iter_trk, pos_int_trk).magnitude()>1e-4) + System.out.printf("%s: iterative helix intercept point at %s (diff to approx: %s) \n", this.getClass().getSimpleName(), pos_iter_trk.toString(), VecOp.sub(pos_iter_trk, pos_int_trk).toString()); + } + + // find position in sensor frame + Hep3Vector pos_iter_sensor = plane.getSensor().getGeometry().getGlobalToLocal().transformed(VecOp.mult(VecOp.inverse(CoordinateTransformations.getMatrix()), pos_iter_trk)); + + if (_debug) { + System.out.printf("%s: found iterative helix intercept in sensor coordinates at %s\n", this.getClass().getSimpleName(), pos_iter_sensor.toString()); + } + + isInside = true; + if (Math.abs(pos_iter_sensor.x()) > plane.getMeasuredDimension() / 2.0) { + if (this._debug) { + System.out.printf("%s: intercept is outside in u\n", this.getClass().getSimpleName()); + } + isInside = false; + } + + if (Math.abs(pos_iter_sensor.y()) > plane.getUnmeasuredDimension() / 2.0) { + if (this._debug) { + System.out.printf("%s: intercept is outside in v\n", this.getClass().getSimpleName()); + } + isInside = false; + } + + if (_debug) { + Hep3Vector pos_iter_det = VecOp.mult(VecOp.inverse(CoordinateTransformations.getMatrix()), pos_iter_trk); + Inside result_inside = plane.getDetectorElement().getGeometry().getPhysicalVolume().getMotherLogicalVolume().getSolid().inside(pos_iter_sensor); + Inside result_inside_module = plane.getSensor().getGeometry().getDetectorElement().getParent().getGeometry().inside(pos_iter_det); + System.out.printf("%s: Inside result sensor: %s module: %s\n", this.getClass().getSimpleName(), result_inside.toString(), result_inside_module.toString()); + + boolean isInsideSolid = false; + if (result_inside.equals(Inside.INSIDE) || result_inside.equals(Inside.SURFACE)) { + isInsideSolid = true; + } + + boolean isInsideSolidModule = false; + if (result_inside_module.equals(Inside.INSIDE) || result_inside_module.equals(Inside.SURFACE)) { + isInsideSolidModule = true; + } + + // Check if it's inside sensor and module and if it contradicts the manual calculation + // For now: trust manual calculation and output warning if it's outside BOTH sensor AND + // module -> FIX THIS!? + if (isInside && !isInsideSolid) { + System.out.printf("%s: manual iterative calculation says inside sensor, inside solid says outside -> contradiction \n", this.getClass().getSimpleName()); + if (isInsideSolidModule) { + System.out.printf("%s: this iterative intercept is outside sensor but inside module\n", this.getClass().getSimpleName()); + } else { + System.out.printf("%s: warning: this iterative intercept %s, sensor frame %s, (sensor origin %s ) is outside sensor and module!\n", this.getClass().getSimpleName(), pos_iter_trk.toString(), pos_iter_sensor.toString(), plane.origin().toString()); + } + } + } + + if (!isInside) { + return null; + } + + if (_debug) { + System.out.printf("%s: found intercept at %s \n", this.getClass().getSimpleName(), pos_iter_trk.toString()); + } + + return pos_iter_trk; + } + + @Override + public void setDebug(boolean debug) { + _debug = debug; + } + + public MaterialManager getMaterialManager() { + // Should be safe to cast here + return (MaterialManager) _materialmanager; + } + + public void fixTrackMomentum(double mom) { + _fixTrackMomentum = true; + _momentum = mom; + } + + /** + * Nested class to encapsulate the scatter angles and which detector element + * it is related to + */ + public class ScatterPoint implements Comparable<ScatterPoint> { + + IDetectorElement _det; + ScatterAngle _scatterAngle; + + public ScatterPoint(IDetectorElement det, ScatterAngle scatterAngle) { + _det = det; + _scatterAngle = scatterAngle; + } + + public IDetectorElement getDet() { + return _det; + } + + public ScatterAngle getScatterAngle() { + return _scatterAngle; + } + + @Override + public int compareTo(ScatterPoint p) { + return p.getScatterAngle().PathLen() > this._scatterAngle.PathLen() ? -1 : 1; + } + } + + /** + * Nested class to encapsulate a list of scatters + * + */ + public class ScatterPoints { + + private List<ScatterPoint> _points; + + public ScatterPoints(List<ScatterPoint> _points) { + this._points = _points; + } + + private ScatterPoints() { + _points = new ArrayList<ScatterPoint>(); + } + + public List<ScatterPoint> getPoints() { + return _points; + } + + public void addPoint(ScatterPoint point) { + _points.add(point); + } + + private List<ScatterAngle> getScatterAngleList() { + List<ScatterAngle> scatters = new ArrayList<ScatterAngle>(); + for (ScatterPoint p : _points) { + scatters.add(p._scatterAngle); + } + return scatters; + } + + public ScatterPoint getScatterPoint(IDetectorElement detectorElement) { + for (ScatterPoint p : _points) { + if (p.getDet().equals(detectorElement)) { + return p; + } + } + return null; + } + } + +} Added: java/sandbox/SvtBiasConstant.java ============================================================================= --- java/sandbox/SvtBiasConstant.java (added) +++ java/sandbox/SvtBiasConstant.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,124 @@ +package org.hps.conditions.svt; + +import java.sql.Timestamp; +import java.util.Date; + +import org.hps.conditions.api.BaseConditionsObject; +import org.hps.conditions.api.BaseConditionsObjectCollection; +import org.hps.conditions.database.Converter; +import org.hps.conditions.database.Field; +import org.hps.conditions.database.MultipleCollectionsAction; +import org.hps.conditions.database.Table; + +/** + * + * Encapsulates an SVT bias constant, which is range in time where bias was ON. + * + * @author Per Hansson Adrian, SLAC + */ +@Table(names = "svt_bias_constants") +@Converter(multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED) +public final class SvtBiasConstant extends BaseConditionsObject { + + /** + * The collection implementation for {@link SvtBiasConstant}. + */ + @SuppressWarnings("serial") + public static class SvtBiasConstantCollection extends BaseConditionsObjectCollection<SvtBiasConstant> { + + /** + * Find bias constant by {@link Timestamp}. + * + * @param date the {@link Timestamp} + * @return the constant containing the date or <code>null</code> otherwise. + * + */ + public SvtBiasConstant find(Timestamp date) { + for (SvtBiasConstant constant : this) { + if(date.getTime() >= constant.getStart() && date.getTime() <= constant.getEnd()) { + return constant; + } + } + return null; + } + + /** + * Find bias constant by {@link Date} type. Converts date to {@link Timestamp} internally. + * + * @param date the {@link Date}. + * @return the constant containing the date or <code>null</code> otherwise. + * + */ + public SvtBiasConstant find(Date date) { + return find(new Timestamp(date.getTime())); + } + } + + private Timestamp getTimeStampFieldValue(String field) { + Object o = fieldValues.get(field); + Timestamp stamp = null; + if(o instanceof Timestamp) + stamp = (Timestamp)o; + else + throw new RuntimeException("the value for field " + field + " is not a Timestamp"); + System.out.println("getTimeStampFieldValue for " + field + " is " + stamp.getTime()); + return stamp; + } + + + + /** + * The start date as a Unix timestamp in milliseconds (GMT). + * + * @return the start date as a Unix timestamp + */ + @Field(names = {"start"}) + public Long getStart() { + return getFieldValue("start"); + } + + /** + * The end date as a Unix timestamp in milliseconds (GMT). + * + * @return the end date as a Unix timestamp + */ + @Field(names = {"end"}) + public Long getEnd() { + return getFieldValue("end"); + } + + /** + * The start {@link Date} based on the {@link Timestamp}. + * This takes care of interfacing to the more used {@link Date} object. + * It is discouraged to treat {@link Timestamp} as type inheritance. + * + * @return the start date. + */ + public Date getStart() { + return new Date(getStartTimestamp().getTime()*1000); + } + + + /** + * The end {@link Date} based on the {@link Timestamp}. + * This takes care of interfacing to the more used {@link Date} object. + * It is discouraged to treat {@link Timestamp} as type inheritance. + * + * @return the start date. + */ + public Date getEnd() { + return new Date(getEndTimestamp().getTime()*1000); + } + + + + /** + * The bias value. + * + * @return the bias value + */ + @Field(names = {"value"}) + public Double getValue() { + return getFieldValue("value"); + } +} Added: java/sandbox/SvtOldHeaderAnalysisDriver.java ============================================================================= --- java/sandbox/SvtOldHeaderAnalysisDriver.java (added) +++ java/sandbox/SvtOldHeaderAnalysisDriver.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,217 @@ +/** + * + */ +package org.hps.users.phansson; + +import hep.aida.IHistogram2D; +import hep.aida.IPlotter; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import java.util.List; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.hps.analysis.trigger.util.TriggerDataUtils; +import org.hps.evio.SvtEvioReader; +import org.hps.evio.SvtEvioUtils; +import org.hps.readout.svt.SvtHeaderDataInfo; +import org.hps.record.triggerbank.AbstractIntData; +import org.hps.record.triggerbank.HeadBankData; +import org.hps.util.BasicLogFormatter; +import org.lcsim.event.EventHeader; +import org.lcsim.event.GenericObject; +import org.lcsim.geometry.Detector; +import org.lcsim.util.Driver; +import org.lcsim.util.aida.AIDA; +import org.lcsim.util.log.LogUtil; + +/** + * @author Per Hansson Adrian <[log in to unmask]> + * + */ +public class SvtOldHeaderAnalysisDriver extends Driver { + + private final AIDA aida = AIDA.defaultInstance(); + + private final String HeaderCollectionName = "SvtHeaders"; + private final Logger logger = LogUtil.create(SvtOldHeaderAnalysisDriver.class.getSimpleName(), new BasicLogFormatter(), Level.INFO); + private int nEventsProcessed = 0; + private Date eventDate = new Date(0); + private IHistogram2D rceSyncErrorCount; + private IHistogram2D rceOFErrorCount; + private IHistogram2D rceSkipCount; + private IHistogram2D rceMultisampleErrorCount; + //private Map< Integer, Map< String, IHistogram1D> > histError = new HashMap< Integer, Map<String, IHistogram1D >>(); + private int nRceSyncErrorCountN = 0; + private int nRceOFErrorCount = 0; + private int nRceSkipCount = 0; + private int nRceMultisampleErrorCount = 0; + private int nRceSvtHeaders = 0; + IPlotter plotter; + + private String logFileName = "dummy.log"; + FileWriter fileWriter; + PrintWriter printWriter; + + private boolean showPlots = false; + private final String triggerBankCollectionName = "TriggerBank"; + + /** + * + */ + public SvtOldHeaderAnalysisDriver() { + + } + + public void setLogFileName(String name) { + this.logFileName = name; + } + + public void setShowPlots(boolean show) { + this.showPlots = show; + } + + @Override + protected void detectorChanged(Detector detector) { + + FileHandler fh; + try { + fh = new FileHandler(logFileName); + logger.addHandler(fh); + fh.setFormatter(new BasicLogFormatter()); + } catch (SecurityException | IOException e1) { + e1.printStackTrace(); + } + + plotter = aida.analysisFactory().createPlotterFactory().create("rceSyncError"); + plotter.createRegions(2, 2); + final int n = SvtEvioReader.MAX_ROC_BANK_TAG+1 - SvtEvioReader.MIN_ROC_BANK_TAG; + rceSyncErrorCount = aida.histogram2D("rceSyncError", n, SvtEvioReader.MIN_ROC_BANK_TAG, SvtEvioReader.MAX_ROC_BANK_TAG+1, 2, 0, 1); + rceOFErrorCount = aida.histogram2D("rceOFError", n, SvtEvioReader.MIN_ROC_BANK_TAG, SvtEvioReader.MAX_ROC_BANK_TAG+1, 2, 0, 1); + rceSkipCount = aida.histogram2D("rceSkipCount", n, SvtEvioReader.MIN_ROC_BANK_TAG, SvtEvioReader.MAX_ROC_BANK_TAG+1, 2, 0, 1); + rceMultisampleErrorCount = aida.histogram2D("rceMultisampleError", n, SvtEvioReader.MIN_ROC_BANK_TAG, SvtEvioReader.MAX_ROC_BANK_TAG+1, 2, 0, 1); + + plotter.region(0).plot(rceSyncErrorCount); + plotter.region(1).plot(rceOFErrorCount); + plotter.region(2).plot(rceSkipCount); + plotter.region(3).plot(rceMultisampleErrorCount); + if(showPlots ) plotter.show(); + + + } + + + @Override + protected void process(EventHeader event) { + + if(event.hasCollection(GenericObject.class, triggerBankCollectionName)) { + Date currentEventDate = TriggerDataUtils.getEventTimeStamp(event, triggerBankCollectionName); + if( currentEventDate == null) { + logger.info("Couldn't get event date from trigger bank for processed " + nEventsProcessed); + // throw new RuntimeException("Couldn't get event date from trigger bank!"); + } else { + eventDate = currentEventDate; + } + } + // log start of run + if( nEventsProcessed == 0 ) + logger.info("startOfRun: run " + event.getRunNumber() + " event " + event.getEventNumber() + " processed " + nEventsProcessed + " date " + eventDate.toString()); + + if( !event.hasCollection(GenericObject.class, HeaderCollectionName) ) + return; + + List<GenericObject> headers = event.get(GenericObject.class, HeaderCollectionName); + + logger.fine("Found " + headers.size() + " SvtHeaders in event " + event.getEventNumber() + " run " + event.getRunNumber()); + + for(GenericObject header : headers ) { + logger.fine("nint " + header.getNInt()); + int roc = SvtHeaderDataInfo.getNum(header); + + // find the errors in the header + int syncError = SvtEvioUtils.getSvtTailSyncErrorBit(SvtHeaderDataInfo.getTail(header)); + int oFError = SvtEvioUtils.getSvtTailOFErrorBit(SvtHeaderDataInfo.getTail(header)); + int skipCount = SvtEvioUtils.getSvtTailMultisampleSkipCount(SvtHeaderDataInfo.getTail(header)); + + // check bits + checkBitValueRange(oFError); + checkBitValueRange(syncError); + + // print header errors to log + if( syncError != 0) { + logger.info("syncError: run " + event.getRunNumber() + " event " + event.getEventNumber() + " date " + " processed " + nEventsProcessed + " date " + eventDate.toString() + + " roc " + roc); + } + if( oFError != 0) { + logger.info("oFError: run " + event.getRunNumber() + " event " + event.getEventNumber() + " date " + " processed " + nEventsProcessed + " date " + eventDate.toString() + + " roc " + roc); + } + for(int i=0; i < skipCount; ++i) { + if( oFError != 0) { + logger.info("skipCount: run " + event.getRunNumber() + " event " + event.getEventNumber() + " date " + " processed " + nEventsProcessed + " date " + eventDate.toString() + + " roc " + roc); + } + } + + + + // Check for multisample tail error bit + int nMultisamples = SvtEvioUtils.getSvtTailMultisampleCount(SvtHeaderDataInfo.getTail(header)); + logger.fine(nMultisamples + " multisamples"); + int multisampleErrorBits = 0; + for(int iMultisample = 0; iMultisample != nMultisamples; ++iMultisample) { + int multisampleHeader = SvtHeaderDataInfo.getMultisample(iMultisample, header); + logger.fine("found multisample tail: " + Integer.toHexString(multisampleHeader)); + int multisampleErrorBit = SvtEvioUtils.getErrorBitFromMultisampleHeader(multisampleHeader); + checkBitValueRange(multisampleErrorBit); + logger.fine("found multisample tail error bit: " + multisampleErrorBit); + if( multisampleErrorBit != 0) { + multisampleErrorBits++; + logger.info("multisample tail error: run " + event.getRunNumber() + " event " + event.getEventNumber() + " date " + eventDate.toString() + + " roc " + roc + " feb " + SvtEvioUtils.getFebIDFromMultisampleTail(multisampleHeader) + + " hybrid " + SvtEvioUtils.getFebHybridIDFromMultisampleTail(multisampleHeader) + + " apv " + SvtEvioUtils.getApvFromMultisampleTail(multisampleHeader)); + } + } + + // keep track how many headers have errors + rceSyncErrorCount.fill(roc, syncError); + rceOFErrorCount.fill(roc, oFError); + rceSkipCount.fill(roc, skipCount); + rceMultisampleErrorCount.fill(roc, multisampleErrorBits > 0 ? 1 : 0); + if( syncError > 0) nRceSyncErrorCountN++; + if( oFError > 0 ) nRceOFErrorCount++; + if( skipCount > 0 ) nRceSkipCount++; + if( multisampleErrorBits > 0 ) nRceMultisampleErrorCount++; + nRceSvtHeaders++; + + + + } + + + nEventsProcessed++; + } + + private void checkBitValueRange(int val) { + if( val != 0 && val != 1) + throw new RuntimeException("invalid value for error bit " + val); + } + + @Override + protected void endOfData() { + logger.info("endOfData: processed " + nEventsProcessed + " date " + eventDate.toString()); + logger.info("nRceSvtHeaders " + nRceSvtHeaders); + logger.info("nRceSyncErrorCountN " + nRceSyncErrorCountN); + logger.info("nRceOFErrorCount " + nRceOFErrorCount); + logger.info("nRceSkipCount " + nRceSkipCount); + logger.info("nRceMultisampleErrorCount " + nRceMultisampleErrorCount); + + } + + +} Added: java/sandbox/SvtOldHeaderDataInfo.java ============================================================================= --- java/sandbox/SvtOldHeaderDataInfo.java (added) +++ java/sandbox/SvtOldHeaderDataInfo.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,119 @@ +/** + * + */ +package org.hps.readout.svt; + +import org.freehep.graphicsio.swf.SWFAction.GetMember; +import org.lcsim.event.GenericObject; + +/** + * @author Per Hansson Adrian <[log in to unmask]> + * + */ +public class SvtOldHeaderDataInfo implements GenericObject { + + private final int num; + private final int header; + private final int tail; + private int[] multisampleheader; + + + + public SvtOldHeaderDataInfo(int num, int header, int tail) { + this.num = num; + this.header = header; + this.tail = tail; + } + + public SvtOldHeaderDataInfo(int num, int header, int tail, int[] multisampleheaders) { + this.num = num; + this.header = header; + this.tail = tail; + this.multisampleheader = multisampleheaders; + } + + public void setMultisampleHeaders(int[] multisampleheaders) { + this.multisampleheader = multisampleheaders; + } + + public int[] getMultisampleHeaders() { + return this.multisampleheader; + } + + public int getMultisampleHeader(int index) { + if( index >= getMultisampleHeaders().length || index < 0) + throw new ArrayIndexOutOfBoundsException(index); + return this.multisampleheader[index]; + } + + public int getNum() { + return this.num; + } + + public int getTail() { + return this.tail; + } + + public int getHeader() { + return this.header; + } + + @Override + public int getNInt() { + return 3 + multisampleheader.length; + } + + @Override + public int getNFloat() { + return 0; + } + + @Override + public int getNDouble() { + return 0; + } + + @Override + public int getIntVal(int index) { + int value; + switch (index) { + case 0: + value = getNum(); + break; + case 1: + value = getHeader(); + break; + case 2: + value = getTail(); + break; + default: + if( (index-3) >= getMultisampleHeaders().length ) + throw new RuntimeException("Invalid index " + Integer.toString(index)); + else + value = getMultisampleHeader(index -3); + break; + } + return value; + } + + + @Override + public float getFloatVal(int index) { + throw new ArrayIndexOutOfBoundsException(); + } + + + @Override + public double getDoubleVal(int index) { + throw new ArrayIndexOutOfBoundsException(); + } + + + @Override + public boolean isFixedSize() { + return true; + } + + + +} Added: java/sandbox/TrackUtils.java ============================================================================= --- java/sandbox/TrackUtils.java (added) +++ java/sandbox/TrackUtils.java Wed Jan 6 08:21:16 2016 @@ -0,0 +1,1197 @@ +package org.hps.recon.tracking; + +import hep.physics.matrix.SymmetricMatrix; +import hep.physics.vec.BasicHep3Vector; +import hep.physics.vec.Hep3Matrix; +import hep.physics.vec.Hep3Vector; +import hep.physics.vec.SpacePoint; +import hep.physics.vec.VecOp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.hps.recon.tracking.EventQuality.Quality; +import org.hps.recon.tracking.gbl.HelicalTrackStripGbl; +import static org.lcsim.constants.Constants.fieldConversion; +import org.lcsim.detector.ITransform3D; +import org.lcsim.detector.solids.Box; +import org.lcsim.detector.solids.Point3D; +import org.lcsim.detector.solids.Polygon3D; +import org.lcsim.detector.tracker.silicon.HpsSiSensor; +import org.lcsim.detector.tracker.silicon.SiSensor; +import org.lcsim.event.EventHeader; +import org.lcsim.event.LCRelation; +import org.lcsim.event.MCParticle; +import org.lcsim.event.RawTrackerHit; +import org.lcsim.event.RelationalTable; +import org.lcsim.event.Track; +import org.lcsim.event.TrackState; +import org.lcsim.event.TrackerHit; +import org.lcsim.event.base.BaseRelationalTable; +import org.lcsim.event.base.BaseTrackState; +import org.lcsim.fit.helicaltrack.HelicalTrackFit; +import org.lcsim.fit.helicaltrack.HelicalTrackHit; +import org.lcsim.fit.helicaltrack.HelicalTrackStrip; +import org.lcsim.fit.helicaltrack.HelixParamCalculator; +import org.lcsim.fit.helicaltrack.HelixUtils; +import org.lcsim.fit.helicaltrack.HitUtils; +import org.lcsim.fit.helicaltrack.MultipleScatter; +import org.lcsim.geometry.Detector; +import org.lcsim.geometry.FieldMap; +import org.lcsim.geometry.subdetector.BarrelEndcapFlag; +import org.lcsim.recon.tracking.seedtracker.SeedCandidate; +import org.lcsim.recon.tracking.seedtracker.SeedTrack; +import org.lcsim.spacegeom.CartesianVector; +import org.lcsim.spacegeom.SpaceVector; +import org.lcsim.util.swim.Helix; +import org.lcsim.util.swim.Line; +import org.lcsim.util.swim.Trajectory; + +/** + * Assorted helper functions for the track and helix objects in lcsim. Re-use as + * much of HelixUtils as possible. + * + * @author Omar Moreno <[log in to unmask]> + */ +// TODO: Switch to tracking/LCsim coordinates for the extrapolation output! +// FIXME: This class should probably be broken up into several different sets of utilities by type. --JM +public class TrackUtils { + + /** + * Private constructor to make class static only + */ + private TrackUtils() { + } + + /** + * Extrapolate track to a position along the x-axis. Turn the track into a + * helix object in order to use HelixUtils. + * + * @param track + * @param x + * @return + */ + public static Hep3Vector extrapolateHelixToXPlane(Track track, double x) { + return extrapolateHelixToXPlane(getHTF(track), x); + } + + /** + * Extrapolate helix to a position along the x-axis. Re-use HelixUtils. + * + * @param track + * @param x + * @return + */ + public static Hep3Vector extrapolateHelixToXPlane(HelicalTrackFit htf, double x) { + double s = HelixUtils.PathToXPlane(htf, x, 0., 0).get(0); + return HelixUtils.PointOnHelix(htf, s); + } + + // ========================================================================== + // Helper functions for track parameters and commonly used derived variables + public static double getPhi(Track track, Hep3Vector position) { + double x = Math.sin(getPhi0(track)) - (1 / getR(track)) * (position.x() - getX0(track)); + double y = Math.cos(getPhi0(track)) + (1 / getR(track)) * (position.y() - getY0(track)); + return Math.atan2(x, y); + } + + public static double getX0(Track track) { + return -1 * getDoca(track) * Math.sin(getPhi0(track)); + } + + public static double getR(Track track) { + return 1.0 / track.getTrackStates().get(0).getOmega(); + } + + public static double getY0(Track track) { + return getDoca(track) * Math.cos(getPhi0(track)); + } + + public static double getDoca(Track track) { + return track.getTrackStates().get(0).getD0(); + } + + public static double getPhi0(Track track) { + return track.getTrackStates().get(0).getPhi(); + } + + public static double getZ0(Track track) { + return track.getTrackStates().get(0).getZ0(); + } + + public static double getTanLambda(Track track) { + return track.getTrackStates().get(0).getTanLambda(); + } + + public static double getSinTheta(Track track) { + return 1 / Math.sqrt(1 + Math.pow(getTanLambda(track), 2)); + } + + public static double getCosTheta(Track track) { + return getTanLambda(track) / Math.sqrt(1 + Math.pow(getTanLambda(track), 2)); + } + + // ========================================================================== + /** + * Calculate the point of interception between the helix and a plane in + * space. Uses an iterative procedure. This function makes assumptions on + * the sign and convecntion of the B-field. Be careful. + * + * @param helfit - helix + * @param unit_vec_normal_to_plane - unit vector normal to the plane + * @param point_on_plane - point on the plane + * @param bfield - magnetic field value + * @return point at intercept + */ + public static Hep3Vector getHelixPlaneIntercept(HelicalTrackFit helfit, Hep3Vector unit_vec_normal_to_plane, Hep3Vector point_on_plane, double bfield) { + boolean debug = false; + //Hep3Vector B = new BasicHep3Vector(0, 0, -1); + //WTrack wtrack = new WTrack(helfit, -1.0*bfield); // + Hep3Vector B = new BasicHep3Vector(0, 0, 1); + WTrack wtrack = new WTrack(helfit, bfield); // + if (debug) { + System.out.printf("getHelixPlaneIntercept:find intercept between plane defined by point on plane %s, unit vec %s, bfield %.3f, h=%s and WTrack \n%s \n", point_on_plane.toString(), unit_vec_normal_to_plane.toString(), bfield, B.toString(), wtrack.toString()); + } + Hep3Vector intercept_point = wtrack.getHelixAndPlaneIntercept(point_on_plane, unit_vec_normal_to_plane, B); + if (debug) { + System.out.printf("getHelixPlaneIntercept: found intercept point at %s\n", intercept_point.toString()); + } + return intercept_point; + } + + + /** + * Calculate the point of interception between the helix and a plane in + * space. Uses an iterative procedure. + * + * @param helfit - helix + * @param strip - strip cluster that will define the plane + * @param bfield - magnetic field value + * @return point at intercept + */ + public static Hep3Vector getHelixPlaneIntercept(HelicalTrackFit helfit, HelicalTrackStripGbl strip, double bfield) { + Hep3Vector point_on_plane = strip.origin(); + Hep3Vector unit_vec_normal_to_plane = VecOp.cross(strip.u(), strip.v());// strip.w(); + Hep3Vector intercept_point = getHelixPlaneIntercept(helfit, unit_vec_normal_to_plane, point_on_plane, bfield); + //double s_origin = HelixUtils.PathToXPlane(helfit, strip.origin().x(), 0., 0).get(0); + //Hep3Vector intercept_point = getHelixPlaneIntercept(helfit, unit_vec_normal_to_plane, point_on_plane, bfield, s_origin); + return intercept_point; + } + + /* + * Calculates the point on the helix in the x-y plane at the intercept with plane The normal of + * the plane is in the same x-y plane as the circle. + * @param helix + * @param vector normal to plane + * @param origin of plane + * @return point in the x-y plane of the intercept + */ + public Hep3Vector getHelixXPlaneIntercept(HelicalTrackFit helix, Hep3Vector w, Hep3Vector origin) { + throw new RuntimeException("this function is not working properly; don't use it"); + + // FInd the intercept point x_int,y_int, between the circle and sensor, which becomes a + // line in the x-y plane in this case. + // y_int = k*x_int + m + // R^2 = (y_int-y_c)^2 + (x_int-x_c)^2 + // solve for x_int + } + + /** + * Get position of a track extrapolated to the HARP in the HPS test run 2012 + * + * @param track + * @return position at HARP + */ + public static Hep3Vector getTrackPositionAtHarp(Track track) { + return extrapolateTrack(track, BeamlineConstants.HARP_POSITION_TESTRUN); + } + + /** + * Get position of a track extrapolated to the ECAL face in the HPS test run + * 2012 + * + * @param track + * @return position at ECAL + */ + public static Hep3Vector getTrackPositionAtEcal(Track track) { + return extrapolateTrack(track, BeamlineConstants.ECAL_FACE); + } + + /** + * Extrapolate track to given position. + * + * @param helix - to be extrapolated + * @param z + * @param useMap + * @param track - position along the x-axis of the helix in lcsim + * coordiantes + * @return + */ + public static Hep3Vector extrapolateTrack(Track track, double z) { + + Hep3Vector trackPosition; + double dz; + if (z >= BeamlineConstants.DIPOLE_EDGE_TESTRUN) { + trackPosition = extrapolateHelixToXPlane(track, BeamlineConstants.DIPOLE_EDGE_TESTRUN); + dz = z - BeamlineConstants.DIPOLE_EDGE_TESTRUN; + } else if (z <= BeamlineConstants.DIPOLE_EDGELOW_TESTRUN) { + trackPosition = extrapolateHelixToXPlane(track, BeamlineConstants.DIPOLE_EDGELOW_TESTRUN); + dz = z - trackPosition.x(); + } else { + Hep3Vector detVecTracking = extrapolateHelixToXPlane(track, z); + // System.out.printf("detVec %s\n", detVecTracking.toString()); + return new BasicHep3Vector(detVecTracking.y(), detVecTracking.z(), detVecTracking.x()); + } + + // Get the track azimuthal angle + double phi = getPhi(track, trackPosition); + + // Find the distance to the point of interest + double r = dz / (getSinTheta(track) * Math.cos(phi)); + double dx = r * getSinTheta(track) * Math.sin(phi); + double dy = r * getCosTheta(track); + + // Find the track position at the point of interest + double x = trackPosition.y() + dx; + double y = trackPosition.z() + dy; + + return new BasicHep3Vector(x, y, z); + } + + /** + * Extrapolate track to given position, using dipole position from geometry. + * + * @param helix - to be extrapolated + * @param track - position along the x-axis of the helix in lcsim + * coordiantes + * @return + */ + public static Hep3Vector extrapolateTrack(Track track, double z, Detector detector) { + + Hep3Vector trackPosition; +// <constant name="dipoleMagnetPositionZ" value="45.72*cm"/> +// <constant name="dipoleMagnetLength" value="108*cm"/> + + double magnetLength = detector.getConstants().get("dipoleMagnetLength").getValue(); + double magnetZ = detector.getConstants().get("dipoleMagnetPositionZ").getValue(); + double magnetDownstreamEdge = magnetZ + magnetLength / 2; + double magnetUpstreamEdge = magnetZ - magnetLength / 2; + if (z >= magnetDownstreamEdge) + trackPosition = extrapolateHelixToXPlane(track, magnetDownstreamEdge); + else if (z <= magnetUpstreamEdge) + trackPosition = extrapolateHelixToXPlane(track, magnetUpstreamEdge); + else { + Hep3Vector detVecTracking = extrapolateHelixToXPlane(track, z); + // System.out.printf("detVec %s\n", detVecTracking.toString()); + return new BasicHep3Vector(detVecTracking.y(), detVecTracking.z(), detVecTracking.x()); + } + double dz = z - trackPosition.x(); + + // Get the track azimuthal angle + double phi = getPhi(track, trackPosition); + + // Find the distance to the point of interest + double r = dz / (getSinTheta(track) * Math.cos(phi)); + double dx = r * getSinTheta(track) * Math.sin(phi); + double dy = r * getCosTheta(track); + + // Find the track position at the point of interest + double x = trackPosition.y() + dx; + double y = trackPosition.z() + dy; + + return new BasicHep3Vector(x, y, z); + } + + /** + * Extrapolate helix to given position + * + * @param helix - to be extrapolated + * @param z - position along the x-axis of the helix in lcsim coordiantes + * @return + */ + public static Hep3Vector extrapolateTrack(HelicalTrackFit helix, double z) { + SeedTrack trk = new SeedTrack(); + // bfield = Math.abs((detector.getFieldMap().getField(new BasicHep3Vector(0, 0, 0)).y())); + double bfield = 0.; + // Here we aren't really using anything related to momentum so B-field is not important + trk.setTrackParameters(helix.parameters(), bfield); // Sets first TrackState. + trk.setCovarianceMatrix(helix.covariance()); // Modifies first TrackState. + trk.setChisq(helix.chisqtot()); + trk.setNDF(helix.ndf()[0] + helix.ndf()[1]); + return TrackUtils.extrapolateTrack(trk, z); + } + + /** + * @param helix input helix object + * @param origin of the plane to intercept + * @param normal of the plane to intercept + * @param eps criteria on the distance to the plane before stopping + * iteration + * @return position in space at the intercept of the plane + */ + public static Hep3Vector getHelixPlanePositionIter(HelicalTrackFit helix, Hep3Vector origin, Hep3Vector normal, double eps) { + boolean debug = false; + if (debug) { + System.out.printf("--- getHelixPlanePositionIter ---\n"); + System.out.printf("Target origin [%.10f %.10f %.10f] normal [%.10f %.10f %.10f]\n", origin.x(), origin.y(), origin.z(), normal.x(), normal.y(), normal.z()); + System.out.printf("%.10f %.10f %.10f %.10f %.10f\n", helix.dca(), helix.z0(), helix.phi0(), helix.slope(), helix.R()); + } + double x = origin.x(); + double d = 9999.9; + double dx = 0.0; + int nIter = 0; + Hep3Vector pos = null; + while (Math.abs(d) > eps && nIter < 50) { + // Calculate position on helix at x + pos = getHelixPosAtX(helix, x + dx); + // Check if we are on the plane + d = VecOp.dot(VecOp.sub(pos, origin), normal); + dx += -1.0 * d / 2.0; + if (debug) + System.out.printf("%d d %.10f pos [%.10f %.10f %.10f] dx %.10f\n", nIter, d, pos.x(), pos.y(), pos.z(), dx); + nIter += 1; + } + return pos; + } + + /* + * Calculates the point on the helix at a given point along the x-axis The normal of the plane + * is in the same x-y plane as the circle. + * @param helix + * @param x point along x-axis + * @return point on helix at x-coordinate + */ + private static Hep3Vector getHelixPosAtX(HelicalTrackFit helix, double x) { + // double C = (double)Math.round(helix.curvature()*1000000)/1000000; + // double R = 1.0/C; + double R = helix.R(); + double dca = helix.dca(); + double z0 = helix.z0(); + double phi0 = helix.phi0(); + double slope = helix.slope(); + // System.out.printf("%.10f %.10f %.10f %.10f %.10f\n",dca,z0,phi0,slope,R); + + double xc = (R - dca) * Math.sin(phi0); + double sinPhi = (xc - x) / R; + double phi_at_x = Math.asin(sinPhi); + double dphi_at_x = phi_at_x - phi0; + if (dphi_at_x > Math.PI) + dphi_at_x -= 2.0 * Math.PI; + if (dphi_at_x < -Math.PI) + dphi_at_x += 2.0 * Math.PI; + double s_at_x = -1.0 * dphi_at_x * R; + double y = dca * Math.cos(phi0) - R * Math.cos(phi0) + R * Math.cos(phi_at_x); + double z = z0 + s_at_x * slope; + BasicHep3Vector pos = new BasicHep3Vector(x, y, z); + // System.out.printf("pos %s xc %f phi_at_x %f dphi_at_x %f s_at_x %f\n", + // pos.toString(),xc,phi_at_x,dphi_at_x,s_at_x); + Hep3Vector posXCheck = TrackUtils.extrapolateHelixToXPlane(helix, x); + if (VecOp.sub(pos, posXCheck).magnitude() > 0.0000001) + throw new RuntimeException(String.format("ERROR the helix propagation equations do not agree? (%f,%f,%f) vs (%f,%f,%f) in HelixUtils", pos.x(), pos.y(), pos.z(), posXCheck.x(), posXCheck.y(), posXCheck.z())); + return pos; + } + + /** + * + */ + public static double findTriangleArea(double x0, double y0, double x1, double y1, double x2, double y2) { + return .5 * (x1 * y2 - y1 * x2 - x0 * y2 + y0 * x2 + x0 * y1 - y0 * x1); + } + + /** + * + */ + public static boolean sensorContainsTrack(Hep3Vector trackPosition, SiSensor sensor) { + boolean debug = false; + ITransform3D localToGlobal = sensor.getGeometry().getLocalToGlobal(); + + Box sensorSolid = (Box) sensor.getGeometry().getLogicalVolume().getSolid(); + Polygon3D sensorFace = sensorSolid.getFacesNormalTo(new BasicHep3Vector(0, 0, 1)).get(0); + if (debug) + System.out.println("sensorContainsTrack: Track Position: " + trackPosition.toString()); + + List<Point3D> vertices = new ArrayList<Point3D>(); + for (int index = 0; index < 4; index++) + vertices.add(new Point3D()); + for (Point3D vertex : sensorFace.getVertices()) + if (vertex.y() < 0 && vertex.x() > 0) { + localToGlobal.transform(vertex); + // vertices.set(0, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + + // sensorPos.y(), vertex.z() + sensorPos.z())); + vertices.set(0, new Point3D(vertex.x(), vertex.y(), vertex.z())); + if (debug) + System.out.println("sensorContainsTrack: Vertex 1 Position: " + vertices.get(0).toString()); // System.out.println("sensorContainsTrack: Transformed Vertex 1 Position: " + // localToGlobal.transformed(vertex).toString()); + } else if (vertex.y() > 0 && vertex.x() > 0) { + localToGlobal.transform(vertex); + // vertices.set(1, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + + // sensorPos.y(), vertex.z() + sensorPos.z())); + vertices.set(1, new Point3D(vertex.x(), vertex.y(), vertex.z())); + if (debug) + System.out.println("sensorContainsTrack: Vertex 2 Position: " + vertices.get(1).toString()); // System.out.println("sensorContainsTrack: Transformed Vertex 2 Position: " + // localToGlobal.transformed(vertex).toString()); + } else if (vertex.y() > 0 && vertex.x() < 0) { + localToGlobal.transform(vertex); + // vertices.set(2, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + + // sensorPos.y(), vertex.z() + sensorPos.z())); + vertices.set(2, new Point3D(vertex.x(), vertex.y(), vertex.z())); + if (debug) + System.out.println("sensorContainsTrack: Vertex 3 Position: " + vertices.get(2).toString()); // System.out.println("sensorContainsTrack: Transformed Vertex 3 Position: " + // localToGlobal.transformed(vertex).toString()); + } else if (vertex.y() < 0 && vertex.x() < 0) { + localToGlobal.transform(vertex); + // vertices.set(3, new Point3D(vertex.y() + sensorPos.x(), vertex.x() + + // sensorPos.y(), vertex.z() + sensorPos.z())); + vertices.set(3, new Point3D(vertex.x(), vertex.y(), vertex.z())); + if (debug) + System.out.println("sensorContainsTrack: Vertex 4 Position: " + vertices.get(3).toString()); // System.out.println("sensorContainsTrack: Transformed Vertex 4 Position: " + // localToGlobal.transformed(vertex).toString()); + } + + double area1 = TrackUtils.findTriangleArea(vertices.get(0).x(), vertices.get(0).y(), vertices.get(1).x(), vertices.get(1).y(), trackPosition.y(), trackPosition.z()); + double area2 = TrackUtils.findTriangleArea(vertices.get(1).x(), vertices.get(1).y(), vertices.get(2).x(), vertices.get(2).y(), trackPosition.y(), trackPosition.z()); + double area3 = TrackUtils.findTriangleArea(vertices.get(2).x(), vertices.get(2).y(), vertices.get(3).x(), vertices.get(3).y(), trackPosition.y(), trackPosition.z()); + double area4 = TrackUtils.findTriangleArea(vertices.get(3).x(), vertices.get(3).y(), vertices.get(0).x(), vertices.get(0).y(), trackPosition.y(), trackPosition.z()); + + return (area1 > 0 && area2 > 0 && area3 > 0 && area4 > 0) || (area1 < 0 && area2 < 0 && area3 < 0 && area4 < 0); + } + + public static Map<String, Double> calculateTrackHitResidual(HelicalTrackHit hth, HelicalTrackFit track, boolean includeMS) { + + boolean debug = false; + Map<String, Double> residuals = new HashMap<String, Double>(); + + Map<HelicalTrackHit, MultipleScatter> msmap = track.ScatterMap(); + double msdrphi = 0; + double msdz = 0; + + if (includeMS) { + msdrphi = msmap.get(hth).drphi(); + msdz = msmap.get(hth).dz(); + } + + // Calculate the residuals that are being used in the track fit + // Start with the bendplane y + double drphi_res = hth.drphi(); + double wrphi = Math.sqrt(drphi_res * drphi_res + msdrphi * msdrphi); + // This is the normal way to get s + double s_wrong = track.PathMap().get(hth); + // This is how I do it with HelicalTrackFits + double s = HelixUtils.PathToXPlane(track, hth.x(), 0, 0).get(0); + // System.out.printf("x %f s %f smap %f\n",hth.x(),s,s_wrong); + if (Double.isNaN(s)) { + double xc = track.xc(); + double RC = track.R(); + System.out.printf("calculateTrackHitResidual: s is NaN. p=%.3f RC=%.3f, x=%.3f, xc=%.3f\n", track.p(-0.491), RC, hth.x(), xc); + return residuals; + } + + Hep3Vector posOnHelix = HelixUtils.PointOnHelix(track, s); + double resy = hth.y() - posOnHelix.y(); + double erry = includeMS ? wrphi : drphi_res; + + // Now the residual for the "measurement" direction z + double resz = hth.z() - posOnHelix.z(); + double dz_res = HitUtils.zres(hth, msmap, track); + double dz_res2 = hth.getCorrectedCovMatrix().diagonal(2); + + if (Double.isNaN(resy)) { + System.out.printf("calculateTrackHitResidual: resy is NaN. hit at %s posOnHelix=%s path=%.3f wrong_path=%.3f helix:\n%s\n", hth.getCorrectedPosition().toString(), posOnHelix.toString(), s, s_wrong, track.toString()); + return residuals; + } + + residuals.put("resy", resy); + residuals.put("erry", erry); + residuals.put("drphi", drphi_res); + residuals.put("msdrphi", msdrphi); + + residuals.put("resz", resz); + residuals.put("errz", dz_res); + residuals.put("dz_res", Math.sqrt(dz_res2)); + residuals.put("msdz", msdz); + + if (debug) { + System.out.printf("calculateTrackHitResidual: HTH hit at (%f,%f,%f)\n", hth.x(), hth.y(), hth.z()); + System.out.printf("calculateTrackHitResidual: helix params d0=%f phi0=%f R=%f z0=%f slope=%f chi2=%f/%f chi2tot=%f\n", track.dca(), track.phi0(), track.R(), track.z0(), track.slope(), track.chisq()[0], track.chisq()[1], track.chisqtot()); + System.out.printf("calculateTrackHitResidual: => resz=%f resy=%f at s=%f\n", resz, resy, s); + // System.out.printf("calculateTrackHitResidual: resy=%f eresy=%f drphi=%f msdrphi=%f \n",resy,erry,drphi_res,msdrphi); + // System.out.printf("calculateTrackHitResidual: resz=%f eresz=%f dz_res=%f msdz=%f \n",resz,dz_res,Math.sqrt(dz_res2),msdz); + } + + return residuals; + } + + public static Map<String, Double> calculateLocalTrackHitResiduals(Track track, HelicalTrackHit hth, HelicalTrackStrip strip, double bFieldInZ) { + HelicalTrackStripGbl stripGbl = new HelicalTrackStripGbl(strip, true); + return calculateLocalTrackHitResiduals(track, hth, stripGbl, bFieldInZ); + } + + public static Map<String, Double> calculateLocalTrackHitResiduals(Track track, HelicalTrackHit hth, HelicalTrackStripGbl strip, double bFieldInZ) { + + SeedTrack st = (SeedTrack) track; + SeedCandidate seed = st.getSeedCandidate(); + HelicalTrackFit _trk = seed.getHelix(); + Map<HelicalTrackHit, MultipleScatter> msmap = seed.getMSMap(); + double msdrdphi = msmap.get(hth).drphi(); + double msdz = msmap.get(hth).dz(); + return calculateLocalTrackHitResiduals(_trk, strip, msdrdphi, msdz, bFieldInZ); + } + + public static Map<String, Double> calculateLocalTrackHitResiduals(HelicalTrackFit _trk, HelicalTrackStrip strip, double bFieldInZ) { + HelicalTrackStripGbl stripGbl = new HelicalTrackStripGbl(strip, true); + return calculateLocalTrackHitResiduals(_trk, stripGbl, 0.0, 0.0, bFieldInZ); + } + + public static Map<String, Double> calculateLocalTrackHitResiduals(HelicalTrackFit _trk, HelicalTrackStripGbl strip, double msdrdphi, double msdz, double bFieldInZ) { + + boolean debug = false; + boolean includeMS = true; + + if (debug) + System.out.printf("calculateLocalTrackHitResiduals: for strip on sensor %s \n", + ((RawTrackerHit) strip.getStrip().rawhits().get(0)).getDetectorElement().getName()); + + Hep3Vector u = strip.u(); + Hep3Vector corigin = strip.origin(); + + // Find interception with plane that the strips belongs to + Hep3Vector trkpos = TrackUtils.getHelixPlaneIntercept(_trk, strip, Math.abs(bFieldInZ)); + + if (debug) { + System.out.printf("calculateLocalTrackHitResiduals: strip u %s origin %s \n", u.toString(), corigin.toString()); + System.out.printf("calculateLocalTrackHitResiduals: found interception point with sensor at %s \n", trkpos.toString()); + } + + if (Double.isNaN(trkpos.x()) || Double.isNaN(trkpos.y()) || Double.isNaN(trkpos.z())) { + System.out.printf("calculateLocalTrackHitResiduals: failed to get interception point (%s) \n", trkpos.toString()); + System.out.printf("calculateLocalTrackHitResiduals: track params\n%s\n", _trk.toString()); + System.out.printf("calculateLocalTrackHitResiduals: track pT=%.3f chi2=[%.3f][%.3f] \n", _trk.pT(bFieldInZ), _trk.chisq()[0], _trk.chisq()[1]); +// trkpos = TrackUtils.getHelixPlaneIntercept(_trk, strip, bFieldInZ); + throw new RuntimeException(); + } + + double xint = trkpos.x(); + double phi0 = _trk.phi0(); + double R = _trk.R(); + double s = HelixUtils.PathToXPlane(_trk, xint, 0, 0).get(0); + double phi = -s / R + phi0; + + Hep3Vector mserr = new BasicHep3Vector(msdrdphi * Math.sin(phi), msdrdphi * Math.sin(phi), msdz); + double msuError = VecOp.dot(mserr, u); + + Hep3Vector vdiffTrk = VecOp.sub(trkpos, corigin); + TrackerHitUtils thu = new TrackerHitUtils(debug); + Hep3Matrix trkToStrip = thu.getTrackToStripRotation(strip.getStrip()); + Hep3Vector vdiff = VecOp.mult(trkToStrip, vdiffTrk); + + double umc = vdiff.x(); + double vmc = vdiff.y(); + double wmc = vdiff.z(); + double umeas = strip.umeas(); + double uError = strip.du(); + double vmeas = 0; + double vError = (strip.vmax() - strip.vmin()) / Math.sqrt(12); + double wmeas = 0; + double wError = 10.0 / Math.sqrt(12); // 0.001; + + if (debug) + System.out.printf("calculateLocalTrackHitResiduals: vdiffTrk %s vdiff %s umc %f umeas %f du %f\n", + vdiffTrk.toString(), vdiff.toString(), umc, umeas, umeas - umc); + + Map<String, Double> res = new HashMap<String, Double>(); + res.put("ures", umeas - umc); + res.put("ureserr", includeMS ? Math.sqrt(uError * uError + msuError * msuError) : uError); + res.put("vres", vmeas - vmc); + res.put("vreserr", vError); + res.put("wres", wmeas - wmc); + res.put("wreserr", wError); + + res.put("vdiffTrky", vdiffTrk.y()); + + return res; + } + + public static int[] getHitsInTopBottom(Track track) { + int n[] = {0, 0}; + List<TrackerHit> hitsOnTrack = track.getTrackerHits(); + for (TrackerHit hit : hitsOnTrack) { + HelicalTrackHit hth = (HelicalTrackHit) hit; + //===> if (SvtUtils.getInstance().isTopLayer((SiSensor) ((RawTrackerHit) hth.getRawHits().get(0)).getDetectorElement())) { + HpsSiSensor sensor = ((HpsSiSensor) ((RawTrackerHit) hth.getRawHits().get(0)).getDetectorElement()); + if (sensor.isTopLayer()) + n[0] = n[0] + 1; + else + n[1] = n[1] + 1; + } + return n; + } + + public static boolean isTopTrack(Track track, int minhits) { + return isTopOrBottomTrack(track, minhits) == 1; + } + + public static boolean isBottomTrack(Track track, int minhits) { + return isTopOrBottomTrack(track, minhits) == 0; + } + + public static int isTopOrBottomTrack(Track track, int minhits) { + int nhits[] = getHitsInTopBottom(track); + if (nhits[0] >= minhits && nhits[1] == 0) + return 1; + else if (nhits[1] >= minhits && nhits[0] == 0) + return 0; + else + return -1; + } + + public static boolean hasTopBotHit(Track track) { + int nhits[] = getHitsInTopBottom(track); + return nhits[0] > 0 && nhits[1] > 0; + } + + public static boolean isSharedHit(TrackerHit hit, List<Track> othertracks) { + HelicalTrackHit hth = (HelicalTrackHit) hit; + for (Track track : othertracks) { + List<TrackerHit> hitsOnTrack = track.getTrackerHits(); + for (TrackerHit loop_hit : hitsOnTrack) { + HelicalTrackHit loop_hth = (HelicalTrackHit) loop_hit; + if (hth.equals(loop_hth)) // System.out.printf("share hit at layer %d at %s (%s) with track w/ chi2=%f\n",hth.Layer(),hth.getCorrectedPosition().toString(),loop_hth.getCorrectedPosition().toString(),track.getChi2()); + + return true; + } + } + return false; + } + + public static int numberOfSharedHits(Track track, List<Track> tracklist) { + List<Track> tracks = new ArrayList<Track>(); + // System.out.printf("%d tracks in event\n",tracklist.size()); + // System.out.printf("look for another track with chi2=%f and px=%f \n",track.getChi2(),track.getTrackStates().get(0).getMomentum()[0]); + for (Track t : tracklist) { + // System.out.printf("add track with chi2=%f and px=%f ?\n",t.getChi2(),t.getTrackStates().get(0).getMomentum()[0]); + if (t.equals(track)) // System.out.printf("NOPE\n"); + + continue; + // System.out.printf("YEPP\n"); + tracks.add(t); + } + List<TrackerHit> hitsOnTrack = track.getTrackerHits(); + int n_shared = 0; + for (TrackerHit hit : hitsOnTrack) + if (isSharedHit(hit, tracks)) + ++n_shared; + return n_shared; + } + + public static boolean hasSharedHits(Track track, List<Track> tracklist) { + return numberOfSharedHits(track, tracklist) != 0; + } + + public static void cut(int cuts[], EventQuality.Cut bit) { + cuts[0] = cuts[0] | (1 << bit.getValue()); + } + + public static boolean isGoodTrack(Track track, List<Track> tracklist, EventQuality.Quality trk_quality) { + int cuts = passTrackSelections(track, tracklist, trk_quality); + return cuts == 0; + } + + public static int passTrackSelections(Track track, List<Track> tracklist, EventQuality.Quality trk_quality) { + int cuts[] = {0}; + if (trk_quality.compareTo(Quality.NONE) != 0) { + if (track.getTrackStates().get(0).getMomentum()[0] < EventQuality.instance().getCutValue(EventQuality.Cut.PZ, trk_quality)) + cut(cuts, EventQuality.Cut.PZ); + if (track.getChi2() >= EventQuality.instance().getCutValue(EventQuality.Cut.CHI2, trk_quality)) + cut(cuts, EventQuality.Cut.CHI2); + if (numberOfSharedHits(track, tracklist) > ((int) Math.round(EventQuality.instance().getCutValue(EventQuality.Cut.SHAREDHIT, trk_quality)))) + cut(cuts, EventQuality.Cut.SHAREDHIT); + if (hasTopBotHit(track)) + cut(cuts, EventQuality.Cut.TOPBOTHIT); + if (track.getTrackerHits().size() < ((int) Math.round(EventQuality.instance().getCutValue(EventQuality.Cut.NHITS, trk_quality)))) + cut(cuts, EventQuality.Cut.NHITS); + } + return cuts[0]; + } + + public static boolean isTopTrack(HelicalTrackFit htf) { + return htf.slope() > 0; + } + + public static boolean isBottomTrack(HelicalTrackFit htf) { + return !isTopTrack(htf); + } + + /** + * Transform MCParticle into a Helix object. Note that it produces the helix + * parameters at nominal x=0 and assumes that there is no field at x<0 + * + * @param mcp MC particle to be transformed + * @return helix object based on the MC particle + */ + public static HelicalTrackFit getHTF(MCParticle mcp, double Bz) { + boolean debug = true; + if (debug) { + System.out.printf("getHTF\n"); + System.out.printf("mcp org %s mc p %s\n", mcp.getOrigin().toString(), mcp.getMomentum().toString()); + } + Hep3Vector org = CoordinateTransformations.transformVectorToTracking(mcp.getOrigin()); + Hep3Vector p = CoordinateTransformations.transformVectorToTracking(mcp.getMomentum()); + + if (debug) + System.out.printf("mcp org %s mc p %s (trans)\n", org.toString(), p.toString()); + + // Move to x=0 if needed + double targetX = BeamlineConstants.DIPOLE_EDGELOW_TESTRUN; + if (org.x() < targetX) { + double dydx = p.y() / p.x(); + double dzdx = p.z() / p.x(); + double delta_x = targetX - org.x(); + double y = delta_x * dydx + org.y(); + double z = delta_x * dzdx + org.z(); + double x = org.x() + delta_x; + if (Math.abs(x - targetX) > 1e-8) + throw new RuntimeException("Error: origin is not zero!"); + org = new BasicHep3Vector(x, y, z); + // System.out.printf("org %s p %s -> org %s\n", + // old.toString(),p.toString(),org.toString()); + } + + if (debug) + System.out.printf("mcp org %s mc p %s (trans2)\n", org.toString(), p.toString()); + + HelixParamCalculator helixParamCalculator = new HelixParamCalculator(p, org, -1 * ((int) mcp.getCharge()), Bz); + double par[] = new double[5]; + par[HelicalTrackFit.dcaIndex] = helixParamCalculator.getDCA(); + par[HelicalTrackFit.slopeIndex] = helixParamCalculator.getSlopeSZPlane(); + par[HelicalTrackFit.phi0Index] = helixParamCalculator.getPhi0(); + par[HelicalTrackFit.curvatureIndex] = 1.0 / helixParamCalculator.getRadius(); + par[HelicalTrackFit.z0Index] = helixParamCalculator.getZ0(); + HelicalTrackFit htf = getHTF(par); + System.out.printf("d0 %f z0 %f R %f phi %f lambda %s\n", + htf.dca(), htf.z0(), htf.R(), htf.phi0(), htf.slope()); + return htf; + } + + public static HelicalTrackFit getHTF(Track track) { + if (track.getClass().isInstance(SeedTrack.class)) + return ((SeedTrack) track).getSeedCandidate().getHelix(); + else + return getHTF(track.getTrackStates().get(0)); + } + + public static HelicalTrackFit getHTF(double par[]) { + // need to have matrix that makes sense? Really? + SymmetricMatrix cov = new SymmetricMatrix(5); + for (int i = 0; i < cov.getNRows(); ++i) + cov.setElement(i, i, 1.); + HelicalTrackFit htf = new HelicalTrackFit(par, cov, new double[2], new int[2], null, null); + return htf; + } + + public static HelicalTrackFit getHTF(TrackState state) { + double par[] = state.getParameters(); + SymmetricMatrix cov = new SymmetricMatrix(5, state.getCovMatrix(), true); + HelicalTrackFit htf = new HelicalTrackFit(par, cov, new double[2], new int[2], null, null); + return htf; + } + + public static StraightLineTrack findSLTAtZ(Track trk1, double zVal, boolean useFringe) { + SeedTrack s1 = (SeedTrack) trk1; + HelicalTrackFit htf1 = s1.getSeedCandidate().getHelix(); + HPSTrack hpstrk1 = new HPSTrack(htf1); + Hep3Vector pos1; + if (useFringe) { + // broken because you need ot provide the Field Map to get this... +// pos1 = hpstrk1.getPositionAtZMap(100.0, zVal, 5.0)[0]; + } else + pos1 = TrackUtils.extrapolateTrack(trk1, zVal); + // System.out.printf("%s: Position1 at edge of fringe %s\n",this.getClass().getSimpleName(),pos1.toString()); + Helix traj = (Helix) hpstrk1.getTrajectory(); + if (traj == null) { + SpacePoint r0 = new SpacePoint(HelixUtils.PointOnHelix(htf1, 0)); + traj = new Helix(r0, htf1.R(), htf1.phi0(), Math.atan(htf1.slope())); + } + HelixConverter converter = new HelixConverter(0.); + StraightLineTrack slt1 = converter.Convert(traj); + // System.out.printf("%s: straight line track: x0=%f,y0=%f,z0=%f dz/dx=%f dydx=%f targetY=%f targetZ=%f \n",this.getClass().getSimpleName(),slt1.x0(),slt1.y0(),slt1.z0(),slt1.dzdx(),slt1.dydx(),slt1.TargetYZ()[0],slt1.TargetYZ()[1]); + return slt1; + } + + public static MCParticle getMatchedTruthParticle(Track track) { + boolean debug = false; + + Map<MCParticle, Integer> particlesOnTrack = new HashMap<MCParticle, Integer>(); + + if (debug) + System.out.printf("getMatchedTruthParticle: getmatched mc particle from %d tracker hits on the track \n", track.getTrackerHits().size()); + + for (TrackerHit hit : track.getTrackerHits()) { + List<MCParticle> mcps = ((HelicalTrackHit) hit).getMCParticles(); + if (mcps == null) + System.out.printf("getMatchedTruthParticle: warning, this hit (layer %d pos=%s) has no mc particles.\n", ((HelicalTrackHit) hit).Layer(), ((HelicalTrackHit) hit).getCorrectedPosition().toString()); + else { + if (debug) + System.out.printf("getMatchedTruthParticle: this hit (layer %d pos=%s) has %d mc particles.\n", ((HelicalTrackHit) hit).Layer(), ((HelicalTrackHit) hit).getCorrectedPosition().toString(), mcps.size()); + for (MCParticle mcp : mcps) { + if (!particlesOnTrack.containsKey(mcp)) + particlesOnTrack.put(mcp, 0); + int c = particlesOnTrack.get(mcp); + particlesOnTrack.put(mcp, c + 1); + } + } + } + if (debug) { + System.out.printf("Track p=[ %f, %f, %f] \n", track.getTrackStates().get(0).getMomentum()[0], track.getTrackStates().get(0).getMomentum()[1], track.getTrackStates().get(0).getMomentum()[1]); + System.out.printf("Found %d particles\n", particlesOnTrack.size()); + for (Map.Entry<MCParticle, Integer> entry : particlesOnTrack.entrySet()) + System.out.printf("%d hits assigned to %d p=%s \n", entry.getValue(), entry.getKey().getPDGID(), entry.getKey().getMomentum().toString()); + } + Map.Entry<MCParticle, Integer> maxEntry = null; + for (Map.Entry<MCParticle, Integer> entry : particlesOnTrack.entrySet()) + if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0) + maxEntry = entry; //if ( maxEntry != null ) { // if(entry.getValue().compareTo(maxEntry.getValue()) < 0) continue; //} + //maxEntry = entry; + if (debug) + if (maxEntry != null) + System.out.printf("Matched particle with pdgId=%d and mom %s to track with charge %d and momentum [%f %f %f]\n", + maxEntry.getKey().getPDGID(), maxEntry.getKey().getMomentum().toString(), + track.getCharge(), track.getTrackStates().get(0).getMomentum()[0], track.getTrackStates().get(0).getMomentum()[1], track.getTrackStates().get(0).getMomentum()[2]); + else + System.out.printf("No truth particle found on this track\n"); + return maxEntry == null ? null : maxEntry.getKey(); + } + + /* + try to make a seed track from a base track + ...some things are irretrivable (tracking strategy).. + and some things I just don't care much about to dig out (det name) + */ + public static SeedTrack makeSeedTrackFromBaseTrack(Track track) { + + TrackState trkState = track.getTrackStates().get(0); + // first make the HelicalTrackFit Object + double[] covArray = trkState.getCovMatrix(); + SymmetricMatrix cov = new SymmetricMatrix(5, covArray, true); + double[] chisq = {track.getChi2(), 0}; + int[] ndf = {track.getNDF(), 0}; + Map<HelicalTrackHit, Double> smap = new HashMap<>(); // just leave these empty + Map<HelicalTrackHit, MultipleScatter> msmap = new HashMap<>();// just leave these empty + double[] pars = {trkState.getD0(), trkState.getPhi(), trkState.getOmega(), trkState.getZ0(), trkState.getTanLambda()}; + HelicalTrackFit htf = new HelicalTrackFit(pars, cov, chisq, ndf, smap, msmap); + // now get the hits and make them helicaltrackhits + List<TrackerHit> rth = track.getTrackerHits(); + List<HelicalTrackHit> hth = new ArrayList<>(); + for (TrackerHit hit : rth) + hth.add(makeHelicalTrackHitFromTrackerHit(hit)); +// SeedCandidate(List<HelicalTrackHit> , SeedStrategy strategy, HelicalTrackFit helix, double bfield) ; + SeedCandidate scand = new SeedCandidate(hth, null, htf, 0.24); + SeedTrack st = new SeedTrack(); + st.setSeedCandidate(scand); + return st; + } + + /* + cast TrackerHit as HTH...this is pretty dumb; just a rearrangment of information + in TrackerHit. The important information that's in HTH but not + in Tracker hit is the HelicalTrackCrosses (and from there the individual strip clusters) + is lost; some work to get them back. + */ + public static HelicalTrackHit makeHelicalTrackHitFromTrackerHit(TrackerHit hit) { + Hep3Vector pos = new BasicHep3Vector(hit.getPosition()); + SymmetricMatrix hitcov = new SymmetricMatrix(3, hit.getCovMatrix(), true); + double dedx = hit.getdEdx(); + double time = hit.getTime(); + int type = hit.getType(); + List rhits = hit.getRawHits(); + String detname = "Foobar"; + int layer = 666; + BarrelEndcapFlag beflag = BarrelEndcapFlag.BARREL; + return new HelicalTrackHit(pos, hitcov, dedx, time, type, rhits, detname, layer, beflag); + } + + public static RelationalTable getHitToStripsTable(EventHeader event) { + RelationalTable hitToStrips = new BaseRelationalTable(RelationalTable.Mode.MANY_TO_MANY, RelationalTable.Weighting.UNWEIGHTED); + List<LCRelation> hitrelations = event.get(LCRelation.class, "HelicalTrackHitRelations"); + for (LCRelation relation : hitrelations) + if (relation != null && relation.getFrom() != null && relation.getTo() != null) + hitToStrips.add(relation.getFrom(), relation.getTo()); + + return hitToStrips; + } + + public static RelationalTable getHitToRotatedTable(EventHeader event) { + + RelationalTable hitToRotated = new BaseRelationalTable(RelationalTable.Mode.ONE_TO_ONE, RelationalTable.Weighting.UNWEIGHTED); + List<LCRelation> rotaterelations = event.get(LCRelation.class, "RotatedHelicalTrackHitRelations"); + for (LCRelation relation : rotaterelations) + if (relation != null && relation.getFrom() != null && relation.getTo() != null) + hitToRotated.add(relation.getFrom(), relation.getTo()); + return hitToRotated; + } + + public static double getTrackTime(Track track, RelationalTable hitToStrips, RelationalTable hitToRotated) { + int nStrips = 0; + double meanTime = 0; + for (TrackerHit hit : track.getTrackerHits()) { + Set<TrackerHit> htsList = hitToStrips.allFrom(hitToRotated.from(hit)); + for (TrackerHit hts : htsList) { + nStrips++; + meanTime += hts.getTime(); + } + } + meanTime /= nStrips; + return meanTime; + } + + public static List<TrackerHit> getStripHits(Track track, RelationalTable hitToStrips, RelationalTable hitToRotated) { + List<TrackerHit> hits = new ArrayList<TrackerHit>(); + for (TrackerHit hit : track.getTrackerHits()) + hits.addAll(hitToStrips.allFrom(hitToRotated.from(hit))); + return hits; + } + + public static boolean hasSharedStrips(Track track1, Track track2, RelationalTable hitToStrips, RelationalTable hitToRotated) { + Set<TrackerHit> track1hits = new HashSet<TrackerHit>(getStripHits(track1, hitToStrips, hitToRotated)); + for (TrackerHit hit : track2.getTrackerHits()) + for (TrackerHit hts : (Set<TrackerHit>) hitToStrips.allFrom(hitToRotated.from(hit))) + if (track1hits.contains(hts)) + return true; + return false; + } + + public static int getLayer(TrackerHit strip) { + return ((RawTrackerHit) strip.getRawHits().get(0)).getLayerNumber(); + } + + /** + * Compute strip isolation, defined as the minimum distance to another strip + * in the same sensor. Strips are only checked if they formed valid crosses + * with the other strip in the cross (passing time and tolerance cuts). + * + * @param strip The strip whose isolation is being calculated. + * @param otherStrip The other strip in the stereo hit. + * @param hitToStrips + * @param hitToRotated + * @return Double_MAX_VALUE if no other strips found. + */ + public static double getIsolation(TrackerHit strip, TrackerHit otherStrip, RelationalTable hitToStrips, RelationalTable hitToRotated) { + double nearestDistance = 99999999.0; + for (TrackerHit cross : (Set<TrackerHit>) hitToStrips.allTo(otherStrip)) + for (TrackerHit crossStrip : (Set<TrackerHit>) hitToStrips.allFrom(cross)) + if (crossStrip != strip && crossStrip != otherStrip) { + int stripMin = Integer.MAX_VALUE; + int stripMax = Integer.MIN_VALUE; + int crossMin = Integer.MAX_VALUE; + int crossMax = Integer.MIN_VALUE; + for (Object rth : strip.getRawHits()) { + int hitStrip = ((RawTrackerHit) rth).getIdentifierFieldValue("strip"); + stripMin = Math.min(stripMin, hitStrip); + stripMax = Math.max(stripMax, hitStrip); + } + for (Object rth : crossStrip.getRawHits()) { + int hitStrip = ((RawTrackerHit) rth).getIdentifierFieldValue("strip"); + crossMin = Math.min(crossMin, hitStrip); + crossMax = Math.max(crossMax, hitStrip); + } + if (stripMin - crossMax <= 1 && crossMin - stripMax <= 1) + continue; //adjacent strips don't count + Hep3Vector stripPosition = new BasicHep3Vector(strip.getPosition()); + Hep3Vector crossStripPosition = new BasicHep3Vector(crossStrip.getPosition()); + double distance = VecOp.sub(stripPosition, crossStripPosition).magnitude(); + if (Math.abs(stripPosition.y()) > Math.abs(crossStripPosition.y())) + distance = -distance; +// System.out.format("%s, %s, %s, %f\n", stripPosition, crossStripPosition, VecOp.sub(stripPosition, crossStripPosition), distance); +// if (distance<=0.0601) continue; //hack to avoid counting adjacent strips that didn't get clustered together +// if (distance<0.1) System.out.format("%d, %d, %f\n",strip.getRawHits().size(),crossStrip.getRawHits().size(), distance); +// if (distance < 0.1) { +// System.out.format("%s, %s, %s, %f\n", stripPosition, crossStripPosition, VecOp.sub(stripPosition, crossStripPosition), distance); +// } + if (Math.abs(distance) < Math.abs(nearestDistance)) + nearestDistance = distance; + } + return nearestDistance; + } + + /** + * Make an array with isolations for all 12 strip layers. If the track + * doesn't use a layer, the isolation is null; if there is no other strip + * hit in a layer, the isolation is Double.MAX_VALUE. + * + * @param trk + * @param hitToStrips + * @param hitToRotated + * @return + */ + public static Double[] getIsolations(Track trk, RelationalTable hitToStrips, RelationalTable hitToRotated) { + Double[] isolations = new Double[12]; + for (TrackerHit hit : trk.getTrackerHits()) { + Set<TrackerHit> htsList = hitToStrips.allFrom(hitToRotated.from(hit)); + TrackerHit[] strips = new TrackerHit[2]; + htsList.toArray(strips); + isolations[TrackUtils.getLayer(strips[0]) - 1] = TrackUtils.getIsolation(strips[0], strips[1], hitToStrips, hitToRotated); + isolations[TrackUtils.getLayer(strips[1]) - 1] = TrackUtils.getIsolation(strips[1], strips[0], hitToStrips, hitToRotated); + } + return isolations; + } + + /** + * iteratively extrapolates a track to a specified value of z using the full + * field map. + * + * @param track + * @param start = value to start extrapolation (use analytic=constant field + * calculation up to here) + * @param zFinal = value to extrapolate to + * @param step = step size + * @param bmap = the field map + * @param debugOk + * @return + */ + public static TrackState extrapolateTrackUsingFieldMap(Track track, double start, double zFinal, double step, FieldMap bmap, boolean debugOk) { + Trajectory _trajectory; + double startFringe = start; + HelicalTrackFit helix = getHTF(track); + + // if looking upstream, we'll be propagating backwards + if (zFinal < 0) + step = -step; + if (debugOk) + System.out.println(track.toString()); + + double sStartFringe = HelixUtils.PathToXPlane(helix, startFringe, 1000.0, 1).get(0); + if (debugOk) + System.out.println("path to end of fringe = " + sStartFringe + "; zFinal = " + zFinal); + double xtmp = startFringe; + double ytmp = HelixUtils.PointOnHelix(helix, sStartFringe).y(); + double ztmp = HelixUtils.PointOnHelix(helix, sStartFringe).z(); + double Rorig = helix.R(); + double xCtmp = helix.xc(); + double yCtmp = helix.yc(); + double q = Math.signum(helix.curvature()); + double phitmp = calculatePhi(xtmp, ytmp, xCtmp, yCtmp, q); + if (debugOk) { + System.out.println("\nOriginal xtmp = " + xtmp + "; ytmp = " + ytmp + "; ztmp = " + ztmp + "; phitmp = " + phitmp); + + System.out.println("nOriginal Rorig = " + Rorig + "; xCtmp = " + xCtmp + "; yCtmp = " + yCtmp); + } + if (debugOk) + System.out.println("Original Direction at Fringe: " + HelixUtils.Direction(helix, startFringe).toString()); + double Rtmp = Rorig; + // now start stepping through the fringe field + Hep3Vector r0Tmp = HelixUtils.PointOnHelix(helix, sStartFringe); + org.lcsim.spacegeom.SpacePoint r0 = new org.lcsim.spacegeom.SpacePoint(r0Tmp); + Hep3Vector bMid = bmap.getField(new BasicHep3Vector(0, 0, 500.0)); + double pTot = helix.p(bMid.y());//50 cm ~ middle of dipole + Hep3Vector dirOrig = HelixUtils.Direction(helix, sStartFringe); + Hep3Vector p0 = VecOp.mult(pTot, dirOrig); + Hep3Vector dirTmp = dirOrig; + org.lcsim.spacegeom.SpacePoint rTmp = r0; + Hep3Vector pTmp = p0; + double pXOrig = p0.x(); + double pXTmp = pXOrig; + double totalS = sStartFringe; + double myBField = bMid.y(); + // follow trajectory while: in fringe field, before end point, and we don't have a looper + while (Math.signum(step) * xtmp < Math.signum(step) * zFinal && Math.signum(pXOrig * pXTmp) > 0) { + if (debugOk) { + System.out.println("New step in Fringe Field"); + System.out.println("rTmp = " + rTmp.toString()); + System.out.println("pTmp = " + pTmp.toString()); + System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(helix, totalS)); + System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(helix, totalS))); + } + + myBField = bmap.getField(new BasicHep3Vector(rTmp.y(), rTmp.z(), rTmp.x())).y(); // note weird co ordinates for track vs det + if (debugOk) + System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField); + _trajectory = getTrajectory(pTmp, rTmp, q, myBField); + rTmp = _trajectory.getPointAtDistance(step); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + xtmp = rTmp.x(); + if (debugOk) { + System.out.println("############## done... #############"); + + System.out.println("\n"); + } + totalS += step; + } + myBField = bmap.getField(new BasicHep3Vector(rTmp.y(), rTmp.z(), rTmp.x())).y(); // note weird co ordinates for track vs det + _trajectory = getTrajectory(pTmp, rTmp, q, myBField); + // Go with finer granularity in the end + rTmp = _trajectory.getPointAtDistance(0); + xtmp = rTmp.x(); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + step = step / 10.0; + + while (Math.signum(step) * xtmp < Math.signum(step) * zFinal && Math.signum(pXOrig * pXTmp) > 0) { + if (debugOk) { + System.out.println("New step in Fringe Field"); + System.out.println("rTmp = " + rTmp.toString()); + System.out.println("pTmp = " + pTmp.toString()); + System.out.println("OriginalHelix pos = " + HelixUtils.PointOnHelix(helix, totalS)); + System.out.println("OriginalHelix Momentum = " + VecOp.mult(pTot, HelixUtils.Direction(helix, totalS))); + } + + myBField = bmap.getField(new BasicHep3Vector(rTmp.y(), rTmp.z(), rTmp.x())).y(); // note weird co ordinates for track vs det + + if (debugOk) + System.out.println("rTmp.x() = " + rTmp.x() + " field = " + myBField); + _trajectory = getTrajectory(pTmp, rTmp, q, myBField); + rTmp = _trajectory.getPointAtDistance(step); + pTmp = VecOp.mult(pTot, _trajectory.getUnitTangentAtLength(step)); + pXTmp = pTmp.x(); + xtmp = rTmp.x(); + if (debugOk) { + System.out.println("############## done... #############"); + System.out.println("\n"); + } + totalS += step; + } + + // ok, done with field. + //store the helical track parameters at rTmp + double pars[] = {Math.sqrt(rTmp.x() * rTmp.x() + rTmp.y() * rTmp.y()), + calculatePhi(pTmp.x(), pTmp.y()), + calculateCurvature(pTmp.magnitude(), q, myBField), + calculateLambda(pTmp.z(), pTmp.magnitude()), + rTmp.z()}; + Hep3Vector pointInTrking = new BasicHep3Vector(rTmp.x(), rTmp.y(), rTmp.z()); + + if (debugOk) + System.out.println("Position xfinal (tracking) : x = " + zFinal + "; y = " + pointInTrking.y() + "; z = " + pointInTrking.z()); + BaseTrackState ts = new BaseTrackState(pars, myBField); + ts.setReferencePoint(pointInTrking.v()); + ts.setLocation(TrackState.AtCalorimeter); + return ts; + } + + public static double calculatePhi(double x, double y, double xc, double yc, double sign) { + return Math.atan2(y - yc, x - xc) - sign * Math.PI / 2; + } + + public static double calculatePhi(double px, double py) { + return Math.atan2(py, px); + } + + public static double calculateLambda(double pz, double p) { + return Math.atan2(pz, p); + } + + public static double calculateCurvature(double p, double q, double B) { + return q * B / p; + } + + public static Trajectory getTrajectory(Hep3Vector p0, org.lcsim.spacegeom.SpacePoint r0, double q, double B) { + SpaceVector p = new CartesianVector(p0.v()); + double phi = Math.atan2(p.y(), p.x()); + double lambda = Math.atan2(p.z(), p.rxy()); + double field = B * fieldConversion; + + if (q != 0 && field != 0) { + double radius = p.rxy() / (q * field); + return new Helix(r0, radius, phi, lambda); + } else + return new Line(r0, phi, lambda); + } + +}