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);
+ }
+
+}
|