Issue

  • Remove problem of how DataOperations are defined in standard by showing how a simple change to the interface can let people do whatever they want!

Proposal

  • For Transform you could read DataOperation!
Proposed addition to Standard
    public interface IExchangeTransform
    {
        IExchangeItem ExchangeItemOriginal { set; get; }
        IExchangeItem ExchangeItemAlternative { get; }
        IValueSet Transform(IValueSet value);
    }

    // Optional Extension for ILinkableComponent

    interface IExchangeTransformable
    {
        int SuggestedTransformsCount { get; }
        IExchangeTransform TransformSugestion(int index);
    }

Example

Example of use
        static void Transforms()
        {
            ITime time = new TimeStamp(10.0);
            string linkid = "wibble";

            // has an output exchange item which returns Reed Growth as a height (IScalar/double)
            ILinkableComponent iLC = new LinkableComponentReedGrowth();

            IValueSet vs = iLC.GetValues(time, linkid);

            double d = ((IScalarSet)vs).GetScalar(0);

            string id = iLC.GetOutputExchangeItem(0).Quantity.ID;
            string idd = iLC.GetOutputExchangeItem(0).Quantity.Description;

            // make 3rd party Linkable component transformable
            LinkableComponentTransformable iLCA = new LinkableComponentTransformable(iLC);

            // change Reed Growth by linear transform y = 10x + 5
            int index = iLCA.AddTransformOutput("ReedGrowthHeight", new LinearTransform(10, 5));

            IValueSet vs2 = iLCA.GetValues(time, linkid);

            double d2 = ((IScalarSet)vs2).GetScalar(0);

            string ida = iLCA.GetOutputExchangeItem(index).Quantity.ID;
            string idda = iLCA.GetOutputExchangeItem(index).Quantity.Description;
        }
Wrap a 3rd Party linkable component to make it Transformable
    class LinkableComponentTransformable : ILinkableComponent
    {
        // Redirect to aggregated linkiable component all members ....

        #region ILinkableComponent Members
        #region IPublisher Members

         // ... except ....

        public LinkableComponentTransformable(ILinkableComponent iLC)
        {
            _iLC = iLC;
        }

        public int OutputExchangeItemCount
        {
            get { return _iLC.OutputExchangeItemCount + _transformedExchangeItems.Count; }
        }

        public IOutputExchangeItem GetOutputExchangeItem(int index)
        {
            if (_transformedExchangeItems.ContainsKey(index))
                return (IOutputExchangeItem)_transformedExchangeItems[index].ExchangeItemAlternative;

            return _iLC.GetOutputExchangeItem(index);
        }

        public IValueSet GetValues(ITime time, string linkID)
        {
            // NOTE: the link must be set up with untransformed exchange item (original) 
              
            IValueSet vs = _iLC.GetValues(time, linkID);

            /*
             * from linkid get iLink
             * from iLink get sourceComponent
             * from iLink get sourceQuantity.ID
             * fudged below ....
             */

            ILinkableComponent iSource = this; // fudge
            string sourceQID = "ReedGrowthHeightLinTran"; // fudge

            int index = -1;

            for (int n = 0; n < iSource.OutputExchangeItemCount; ++n)
            {
                if (iSource.GetOutputExchangeItem(n).Quantity.ID == sourceQID)
                    index = n;
            }

            if (index > -1)
            {
                if (_transformedExchangeItems.ContainsKey(index))
                    return _transformedExchangeItems[index].Transform(vs);
            }

            return vs;
        }

        // New Members

        public int AddTransformOutput(string quantityId, IExchangeTransform transform)
        {
            // Not recursive ie no transforms on transforms but could be done
            int index = OutputExchangeItemCount + _transformedExchangeItems.Count;

            for (int n = 0; n < OutputExchangeItemCount; ++n)
            {
                if (GetOutputExchangeItem(n).Quantity.ID == quantityId)
                {
                    transform.ExchangeItemOriginal = GetOutputExchangeItem(n);
                    _transformedExchangeItems.Add(index, transform);
                    return index;
                }
            }

            return -1;
        }

        Dictionary<int, IExchangeTransform> _transformedExchangeItems = new Dictionary<int, IExchangeTransform>();
        ILinkableComponent _iLC;
    }
Quantity for a Linear Transform
    class QuantityLinearTransform : IQuantity
    {
        IQuantity _quantity;

        public QuantityLinearTransform(IQuantity q)
        {
            _quantity = q;
        }

        #region IQuantity Members

        public string ID
        {
            get { return _quantity.ID + "LinTran"; }
        }

        public string Description
        {
            get { return _quantity.Description + " Linear Transform"; }
        }

        public org.OpenMI.Standard.ValueType ValueType
        {
            get { return _quantity.ValueType; }
        }

        public IDimension Dimension
        {
            get { return _quantity.Dimension; }
        }

        public IUnit Unit
        {
            get { return _quantity.Unit; }
        }

        #endregion
    }
A Linear Transform
    class LinearTransform : IExchangeTransform
    {
        double _a = 1;
        double _b = 0;

        IExchangeItem _original;
        IExchangeItem _new;

        public LinearTransform(double a, double b)
        {
            _a = a;
            _b = b;
        }

        #region IAdaptor Members

        public IValueSet Transform(IValueSet value)
        {
            double x = ((IScalarSet)value).GetScalar(0);
            double y =  _a*x + _b;
            return new Double(y);
        }

        public IExchangeItem ExchangeItemOriginal 
        {
            set 
            {
                _original = value;

                if (value is IOutputExchangeItem)
                    _new = new OutputExchangeItem(new QuantityLinearTransform(_original.Quantity), _original.ElementSet);
                else
                {
                    Debug.Assert(false);
                }
            }

            get { return _original; }
        }

        public IExchangeItem ExchangeItemAlternative
        {
            get { return _new; }
        }

        #endregion
    }
Other classes
SEE ADAPTER EXAMPLE