Click or drag to resize

Archiving

While the primary purpose of Tracking Library is the ability to perform analysis and visualization as data is received, it also contains a set of classes for archiving received data for later analysis and review.

Note Note

The functionality described in this topic requires a license for the Tracking Library.

Archiving Entities

TrackingArchive<TEntity> is an abstract base class that archives entities. The following implementations are provided:

You can create your own archiver by deriving from TrackingArchive<TEntity> and implementing the required methods. Data can be retrieved from an archive in several formats: raw property data, an entity, a DateMotionCollection<T>, a DateMotionCollection<T, TDerivative>, a Point, or an Axes.

Entity Schema

In order for an entity to be used by an archiver, an entity schema and set of archivers must be defined. These items are registered using the EntityDescriptor<TEntity> class, which is described in more detail in the Entities topic. By implementing the IEntityArchiveDescriptor<TEntity> interface, you control exactly what data gets written to and read from an archive.

The schema defines which properties are stored in the archive, and their names. The archivers define how to store a particular type of value in archive.

The following code sample defines an entity descriptor that implements IEntityArchiveDescriptor<TEntity>. The schema and archivers are configured in the constructor.

C#
public class ExampleEntityDescriptorWithArchive : EntityDescriptor<ExampleEntity>,
                                                  IEntityPositionDescriptor,
                                                  IEntityOrientationDescriptor,
                                                  IEntityArchiveDescriptor<ExampleEntity>
{
    public ExampleEntityDescriptorWithArchive()
    {
        //Schema
        m_schema = new EntitySchema<ExampleEntity>(typeof(string));
        CommonEntityInterfaces.IEntityLastUpdate.AddToSchema(m_schema);
        CommonEntityInterfaces.IEntityVelocity.AddToSchema(m_schema);
        CommonEntityInterfaces.IEntityOrientation.AddToSchema(m_schema);
        m_schema.AddProperty("SymbolId", entity => entity.SymbolId);
        m_schema.AddProperty("Affiliation", entity => entity.Affiliation);

        //Archivers
        m_archivers = new TrackingTypeArchiverCollection();
        m_archivers.AddEnumeration<Force>();
        m_archivers.Freeze();
    }

    public ReferenceFrame PositionReferenceFrame
    {
        get { return CentralBodiesFacet.GetFromContext().Earth.FixedFrame; }
    }

    public Axes OrientationAxes
    {
        get { return PositionReferenceFrame.Axes; }
    }

    public EntitySchema<ExampleEntity> Schema
    {
        get { return m_schema; }
    }

    public TrackingTypeArchiverCollection Archivers
    {
        get { return m_archivers; }
    }

    public ExampleEntity CreateEntity(TransactionContext context, object entityIdentifier)
    {
        return new ExampleEntity(context, (string)entityIdentifier);
    }

    private readonly EntitySchema<ExampleEntity> m_schema;
    private readonly TrackingTypeArchiverCollection m_archivers;
}

The schema is defined by constructing a EntitySchema<TEntity>, passing in the type of the EntityIdentifier property. For each standard interface that the entity implements, AddToSchema is called on the equivalent static class in CommonEntityInterfaces, in order to add the properties that correspond to that particular interface to the schema. Once the standard interfaces are defined in the schema, any remaining properties are then added by calling AddPropertyT, passing the name of the property and a delegate that will get the value of the property from an entity. After the schema is defined, the set of TrackingTypeArchivers which can read and write entity data must also be defined. By default, TrackingTypeArchiverCollection already contains archivers which can handle all primitive types, as well as most Components immutable types and enums. In the above example, the Force enum is the only non-standard type, so it is added by calling the AddEnumerationT method. This will cause the enum to be treated as an integer. If a more complex type needs to be archived, you can implement a custom archiver by deriving from TrackingTypeArchiver.

In most cases, the default archivers simply read and write the underlying numeric properties from the data structure. For example, the Cartesian archiver produces three double values containing X, Y, and Z. Several archivers perform other transformations you may need to be aware of:

Writing to an Archive

After registering an EntityDescriptor<TEntity> for a given entity type, we can create an archive and start writing entities to that archive, as shown in the following code sample:

C#
var archive = new SqlServerArchive<ExampleEntity>(context, connectionString, tableName);
archive.StartWriting();

The above code sample uses SqlServerArchive<TEntity>, but MemoryArchive<TEntity> works the same way, as shown in the following code sample:

C#
var archive = new MemoryArchive<ExampleEntity>(context);
archive.StartWriting();

Any entity of the specified type that is created or modified using the specified TransactionContext will be written to the archive until StopWriting is called.

Retrieving Archived Data

Assuming an archive was created as in the above code sample, data can be retrieved in several ways. The most basic way is to retrieve RawEntityData<TEntity>, objects by calling the GetArchivedData method. The following code sample takes an entity identifier, start time, stop time, maximum number of records, and list of properties to retrieve.

C#
object entityId = "Maverick";
JulianDate startTime = new JulianDate(new GregorianDate(2010, 5, 7, 0, 0, 0.0));
JulianDate stopTime = startTime.AddDays(1.0);

var archive = new MemoryArchive<ExampleEntity>(context);

RawEntityData<ExampleEntity> rawData =
    archive.GetArchivedData(entityId, startTime, stopTime, int.MaxValue,
                            CommonEntityInterfaces.IEntityLastUpdate.LastUpdateName,
                            CommonEntityInterfaces.IEntityPosition.PositionName,
                            "SymbolId");

for (int i = 0; i < rawData.RecordCount; i++)
{
    object[] values = rawData.GetValues(i);
    JulianDate lastUpdate = (JulianDate)values[0];
    Cartesian position = (Cartesian)values[1];
    string symbolId = (string)values[2];
}

The original entity that was archived can then be reconstructed by calling the CreateEntity method. Note that only the properties which were retrieved from the archive when GetArchivedData was called will be set on the entity. To create a complete entity, all properties must be specified.

C#
RawEntityData<ExampleEntity> rawData =
    archive.GetArchivedData(entityId, startTime, stopTime, int.MaxValue,
                            CommonEntityInterfaces.IEntityIdentifier.EntityIdentifierName,
                            CommonEntityInterfaces.IEntityLastUpdate.LastUpdateName,
                            CommonEntityInterfaces.IEntityPosition.PositionName,
                            CommonEntityInterfaces.IEntityVelocity.VelocityName,
                            "SymbolId",
                            "Affiliation");

context.DoTransactionally(transaction =>
{
    for (int j = 0; j < rawData.RecordCount; j++)
    {
        ExampleEntity entity = rawData.CreateEntity(j, transaction);
    }
});

A DateMotionCollection<T> can also be constructed from the archive, as shown in the following code sample:

C#
DateMotionCollection<Cartesian> motions =
    archive.GetMotion<Cartesian>(entityId, startTime, stopTime,
                                 CommonEntityInterfaces.IEntityPosition.PositionName,
                                 CommonEntityInterfaces.IEntityVelocity.VelocityName);

Finally, PointFromArchive<TEntity> and AxesFromArchive<TEntity> are available, which implement Point and Axes, respectively. These classes access data directly from the archive on demand, allowing you to create Platforms and other objects that use archived data for analysis.

C#
PointFromArchive<ExampleEntity> entityPoint = new PointFromArchive<ExampleEntity>(archive, entityId);
AxesFromArchive<ExampleEntity> entityAxes = new AxesFromArchive<ExampleEntity>(archive, entityId);

Platform platform = new Platform
{
    LocationPoint = entityPoint,
    OrientationAxes = entityAxes
};