1 #ifndef OPENSIM_COMPONENT_OUTPUT_H_
2 #define OPENSIM_COMPONENT_OUTPUT_H_
3 /* -------------------------------------------------------------------------- *
4  *                      OpenSim:  ComponentOutput.h                           *
5  * -------------------------------------------------------------------------- *
6  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
7  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
8  * OpenSim is developed at Stanford University and supported by the US        *
9  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
10  * through the Warrior Web program.                                           *
11  *                                                                            *
12  * Copyright (c) 2005-2017 Stanford University and the Authors                *
13  * Author(s): Ajay Seth                                                       *
14  *                                                                            *
15  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
16  * not use this file except in compliance with the License. You may obtain a  *
17  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
18  *                                                                            *
19  * Unless required by applicable law or agreed to in writing, software        *
20  * distributed under the License is distributed on an "AS IS" BASIS,          *
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
22  * See the License for the specific language governing permissions and        *
23  * limitations under the License.                                             *
24  * -------------------------------------------------------------------------- */
25 
26 /** @file
27  * This file defines the Output class, which formalizes an output (signal)
28  * that a Component produces. This can be the tension in a force element, the
29  * location of a body, metabolic energy consumption of a model, etc...
30  * It is the obligation of the Component to define its outputs.
31  */
32 
33 // INCLUDES
34 #include "Exception.h"
35 #include "Object.h"
36 
37 #include <functional>
38 #include <map>
39 
40 #include <SimTKcommon/internal/Stage.h>
41 #include <SimTKcommon/internal/State.h>
42 
43 namespace OpenSim {
44 
45 class Component;
46 class AbstractInput;
47 
48 /** One of the values of an Output. */
49 class AbstractChannel {
50 public:
51     virtual ~AbstractChannel() = default;
52     /** The name of this channel, or the name of the output that
53     contains this Channel if it's in a single-value Output. */
54     virtual const std::string& getChannelName() const = 0;
55     /** The name of the value type (e.g., `double`) produced by this channel. */
56     virtual std::string getTypeName() const = 0;
57     /** The name of this channel appended to the name of the output that
58      * contains this channel. The output name and channel name are separated by
59      * a colon (e.g., "markers:medial_knee"). If the output that contains
60      * this channel is a single-value Output, then this is just the Output's
61      * name. */
62     virtual std::string getName() const = 0;
63     /** This returns the absolute path name of the component to which this channel
64      * belongs prepended to the channel's name. For example, this
65      * method might return something like "/model/metabolics|heat_rate:soleus_r".
66      */
67     virtual std::string getPathName() const = 0;
68 };
69 
70 
71 //=============================================================================
72 //                           OPENSIM COMPONENT OUTPUT
73 //=============================================================================
74 /**
75  * Output formalizes the access to a value of interest computed by the
76  * owning Component. The value is then exposed and easily accessible for use by
77  * other components (e.g. to satisfy an Input).
78  * The purpose of an Output is to bind a value of interest to a component's
79  * member function (generator), and provide a generic interface to the value,
80  * its type and label so it can be easily identified. It also specifies the
81  * realization (computational) stage at which the value is valid, so that a
82  * caller can provide adequate error handling.
83  *
84  * For example, a Body can have its position transformation with respect to
85  * ground as an Output, which is only accessible when the model has been
86  * realized to the Position stage or beyond, in which case it depends on the
87  * Position stage. The validity of data flow can be checked prior to
88  * initiating a simulation.
89  *
90  * An Output is intended to lightweight and adds no computational overhead
91  * if the output goes unused. When an Output's value is called upon,
92  * the overhead is a single redirect to the corresponding member function
93  * for the value.
94  *
95  * An Output can either be a single-value Output or a list Output. A list Output
96  * is one that can have multiple Channels. The Channels are what get connected
97  * to Inputs.
98  * @author  Ajay Seth
99  */
100 
101 class OSIMCOMMON_API AbstractOutput {
102 public:
AbstractOutput()103     AbstractOutput() : dependsOnStage(SimTK::Stage::Infinity) {}
AbstractOutput(const std::string & name,SimTK::Stage dependsOnStage,bool isList)104     AbstractOutput(const std::string& name, SimTK::Stage dependsOnStage,
105                    bool isList) :
106         name(name), dependsOnStage(dependsOnStage), _isList(isList) {}
~AbstractOutput()107     virtual ~AbstractOutput() { }
108 
109     /** Output's name */
getName()110     const std::string& getName() const { return name; }
111     /** Output's dependence on System being realized to at least this System::Stage */
getDependsOnStage()112     const SimTK::Stage& getDependsOnStage() const { return dependsOnStage; }
113     /** Can this Output have more than one channel? */
isListOutput()114     bool isListOutput() const { return _isList; }
115 
116     /** Output's owning Component */
getOwner()117     const Component& getOwner() const { return _owner.getRef(); }
118 
119     /** This returns <absolute-path-to-component>|<output-name>. */
120     std::string getPathName() const;
121 
122     /** Output Interface */
123 
124     /** Remove all channels from this Output (for list Outputs). */
125     virtual void clearChannels() = 0;
126     /** Add a channel to this Output. This should be called within the
127      * component's extendFinalizeFromProperties() .*/
128     virtual void addChannel(const std::string& channelName) = 0;
129     virtual const AbstractChannel& getChannel(const std::string& name) const = 0;
130 
131     /** The name of the value type (e.g., `double`) produced by this output. */
132     virtual std::string     getTypeName() const = 0;
133     virtual std::string     getValueAsString(const SimTK::State& state) const = 0;
134     virtual bool        isCompatible(const AbstractOutput&) const = 0;
135     virtual void compatibleAssign(const AbstractOutput&) = 0;
136 
137     AbstractOutput& operator=(const AbstractOutput& o)
138     { compatibleAssign(o); return *this; }
139 
140     virtual AbstractOutput* clone() const = 0;
141 
142     /** Specification for number of significant figures in string value. */
getNumberOfSignificantDigits()143     unsigned int getNumberOfSignificantDigits() const { return _numSigFigs; }
setNumberOfSignificantDigits(unsigned int numSigFigs)144     void         setNumberOfSignificantDigits(unsigned int numSigFigs)
145     { _numSigFigs = numSigFigs; }
146 
147 protected:
148 
149     // Set the component that contains this Output.
setOwner(const Component & owner)150     void setOwner(const Component& owner) {
151         _owner.reset(&owner);
152     }
153 
154     SimTK::ReferencePtr<const Component> _owner;
155 
156 private:
157     std::string name;
158     SimTK::Stage dependsOnStage;
159     unsigned int _numSigFigs = 8;
160     bool _isList = false;
161 
162     // For calling setOwner().
163     friend Component;
164 //=============================================================================
165 };  // END class AbstractOutput
166 
167 template<class T>
168 class Output : public AbstractOutput {
169 public:
170 
171     /// The concrete Channel type that corresponds to Output<T>.
172     class Channel;
173 
174     /// The container type that holds onto all of Channels in an Output.
175     typedef std::map<std::string, Channel> ChannelMap;
176 
177     //default construct output function pointer and result container
Output()178     Output() {}
179     /** Convenience constructor
180     Create a Component::Output bound to a specific method of the Component and
181     valid at a given realization Stage.
182     @param name             The name of the output.
183     @param outputFunction   The output function to be invoked (returns Output T)
184     @param dependsOnStage   Stage at which Output can be evaluated.
185     @param isList           Can this Output have more than one channel? */
Output(const std::string & name,const std::function<void (const Component * comp,const SimTK::State &,const std::string & channel,T &)> & outputFunction,const SimTK::Stage & dependsOnStage,bool isList)186     explicit Output(const std::string& name,
187         const std::function<void (const Component* comp,
188                                  const SimTK::State&,
189                                  const std::string& channel, T&)>& outputFunction,
190         const SimTK::Stage&     dependsOnStage,
191         bool                    isList) :
192             AbstractOutput(name, dependsOnStage, isList),
193             _outputFcn(outputFunction) {
194         if (!isList) {
195             // We want just one channel with an empty name.
196             _channels[""] = Channel(this, "");
197         }
198 
199     }
200 
201     /** Custom copy constructor is for setting the Channel's pointer
202      * back to this Output. */
Output(const Output & source)203     Output(const Output& source) : AbstractOutput(source),
204             _outputFcn(source._outputFcn), _channels(source._channels) {
205         for (auto& it : _channels) {
206             it.second._output.reset(this);
207         }
208     }
209 
210     /** Custom copy assignment operator is for setting the Channel's pointer
211      * back to this Output. */
212     Output& operator=(const Output& source) {
213         if (&source == this) return *this;
214         AbstractOutput::operator=(source);
215         _outputFcn = source._outputFcn;
216         _channels = source._channels;
217         for (auto& it : _channels) {
218             it.second._output.reset(this);
219         }
220         return *this;
221     }
222 
~Output()223     virtual ~Output() {}
224 
225     // TODO someone more knowledgeable could try to implement these.
226     Output(Output&&) = delete;
227     Output& operator=(Output&&) = delete;
228 
isCompatible(const AbstractOutput & o)229     bool isCompatible(const AbstractOutput& o) const override { return isA(o); }
compatibleAssign(const AbstractOutput & o)230     void compatibleAssign(const AbstractOutput& o) override {
231         if (!isA(o))
232             SimTK_THROW2(SimTK::Exception::IncompatibleValues,
233                          o.getTypeName(), getTypeName());
234         *this = downcast(o);
235     }
236 
clearChannels()237     void clearChannels() override {
238         if (!isListOutput())
239             throw Exception("Cannot clear Channels of single-value Output.");
240         _channels.clear();
241     }
242 
addChannel(const std::string & channelName)243     void addChannel(const std::string& channelName) override {
244         if (!isListOutput())
245             throw Exception("Cannot add Channels to single-value Output.");
246         if (channelName.empty())
247             throw Exception("Channel name cannot be empty.");
248         _channels[channelName] = Channel(this, channelName);
249     }
250 
251     /** For a single-value output, name must be empty or must be the output's
252      * name. */
getChannel(const std::string & name)253     const AbstractChannel& getChannel(const std::string& name) const override {
254         try {
255             if (!isListOutput() && name == getName()) return _channels.at("");
256             return _channels.at(name);
257         } catch (const std::out_of_range&) {
258             OPENSIM_THROW(Exception, "Output '" + getName() + "' does not have "
259                           "a channel named '" + name + "'.");
260         }
261     }
262 
263     /** Use this to iterate through this Output's channels
264      (even for single-value Channels).
265 
266      @code{.cpp}
267      for (const auto& chan : getChannels()) {
268         std::cout << chan.second->getName() << std::endl;
269      }
270      @endcode
271      */
getChannels()272     const ChannelMap& getChannels() const { return _channels; }
273 
274     //--------------------------------------------------------------------------
275     // OUTPUT VALUE
276     //--------------------------------------------------------------------------
277     /** Return the Value of this output if the state is appropriately realized
278         to a stage at or beyond the dependsOnStage, otherwise expect an
279         Exception. */
getValue(const SimTK::State & state)280     const T& getValue(const SimTK::State& state) const {
281         if (isListOutput()) {
282             throw Exception("Cannot get value for list Output. "
283                             "Ask a specific channel for its value.");
284         }
285         if (state.getSystemStage() < getDependsOnStage())
286         {
287             throw SimTK::Exception::StageTooLow(__FILE__, __LINE__,
288                     state.getSystemStage(), getDependsOnStage(),
289                     "Output::getValue(state)");
290         }
291         _outputFcn(_owner.get(), state, "", _result);
292         return _result;
293     }
294 
getTypeName()295     std::string getTypeName() const override {
296         return OpenSim::Object_GetClassName<T>::name();
297     }
298 
getValueAsString(const SimTK::State & state)299     std::string getValueAsString(const SimTK::State& state) const override {
300         if (isListOutput()) {
301             throw Exception("Cannot get value for list Output. "
302                             "Ask a specific channel for its value.");
303         }
304         unsigned int ns = getNumberOfSignificantDigits();
305         std::stringstream s;
306         s << std::setprecision(ns) << getValue(state);
307         return s.str();
308     }
309 
clone()310     Output<T>* clone() const override { return new Output(*this); }
311     SimTK_DOWNCAST(Output, AbstractOutput);
312 
313     /** For use in python/java/MATLAB bindings. */
314     // This method exists for consistency with Object's safeDownCast.
safeDownCast(AbstractOutput * parent)315     static Output<T>* safeDownCast(AbstractOutput* parent) {
316         return dynamic_cast<Output<T>*>(parent);
317     }
318 
319 private:
320     mutable T _result;
321     std::function<void (const Component*,
322                         const SimTK::State&,
323                         const std::string& channel,
324                         T& result)> _outputFcn { nullptr };
325     // TODO consider using indices, and having a parallel data structure
326     // for names.
327     std::map<std::string, Channel> _channels;
328 
329 //=============================================================================
330 };  // END class Output
331 
332 
333 template <typename T>
334 class Output<T>::Channel : public AbstractChannel {
335 public:
336     Channel() = default;
Channel(const Output<T> * output,const std::string & channelName)337     Channel(const Output<T>* output, const std::string& channelName)
338      : _output(output), _channelName(channelName) {}
getValue(const SimTK::State & state)339     const T& getValue(const SimTK::State& state) const {
340         // Must cache, since we're returning a reference.
341         _output->_outputFcn(_output->_owner.get(), state, _channelName, _result);
342         return _result;
343     }
getOutput()344     const Output<T>& getOutput() const { return _output.getRef(); }
getChannelName()345     const std::string& getChannelName() const override {
346         if (_channelName.empty()) return getOutput().getName();
347         return _channelName;
348     }
getTypeName()349     std::string getTypeName() const override {
350         return getOutput().getTypeName();
351     }
getName()352     std::string getName() const override {
353         if (_channelName.empty()) return getOutput().getName();
354         return getOutput().getName() + ":" + _channelName;
355     }
getPathName()356     std::string getPathName() const override {
357         return getOutput().getOwner().getAbsolutePathString() + "|" + getName();
358     }
359 private:
360     mutable T _result;
361     SimTK::ReferencePtr<const Output<T>> _output;
362     std::string _channelName;
363 
364 #ifndef SWIG // These declarations cause a warning in SWIG.
365     // To allow Output<T> to set the _output pointer upon copy.
366     friend Output<T>::Output(const Output&);
367     friend Output<T>& Output<T>::operator=(const Output&);
368 #endif
369 };
370 
371 // TODO consider using std::reference_wrapper<T> as type for _output_##oname,
372 // since it is copyable.
373 
374 /// @name Creating Outputs for your Component
375 /// Use these macros at the top of your component class declaration,
376 /// near where you declare @ref Property properties.
377 /// @{
378 /** Create an output for a member function of this component.
379  *  The following must be true about componentMemberFunction, the function
380  *  that returns the output:
381  *
382  *     -# It is a member function of your component.
383  *     -# The member function is const.
384  *     -# It takes only one argument, which is `const SimTK::State&`.
385  *     -# The function returns the computed quantity *by value* (e.g.,
386  *        `double computeQuantity(const SimTK::State&) const`).
387  *
388  *  You must also provide the stage on which the output depends.
389  *
390  *  Here's an example for using this macro:
391  *  @code{.cpp}
392  *  class MyComponent : public Component {
393  *  public:
394  *      OpenSim_DECLARE_OUTPUT(force, double, getForce, SimTK::Stage::Dynamics);
395  *      ...
396  *  };
397  *  @endcode
398  *
399  *  @warning The fourth requirement above can be lifted if the function returns
400  *  a quantity that is stored in the provided SimTK::State (as a state
401  *  variable, cache variable, etc.); in this case, your function's return type
402  *  should be `const T&` (e.g, `const double&`). If your function returns a
403  *  `const T&` but the quantity is NOT stored in the provided SimTK::State, the
404  *  output value will be invalid!
405  *
406  * @see Component::constructOutput()
407  * @relates OpenSim::Output
408  */
409 #define OpenSim_DECLARE_OUTPUT(oname, T, func, ostage)                      \
410     /** @name Outputs                                                    */ \
411     /** @{                                                               */ \
412     /** Provides the value of func##() and is available at stage ostage. */ \
413     /** This output was generated with the                               */ \
414     /** #OpenSim_DECLARE_OUTPUT macro.                                   */ \
415     OpenSim_DOXYGEN_Q_PROPERTY(T, oname)                                    \
416     /** @}                                                               */ \
417     /** @cond                                                            */ \
418     bool _has_output_##oname {                                              \
419         this->template constructOutput<T>(#oname, &Self::func, ostage)      \
420     };                                                                      \
421     /** @endcond                                                         */
422 
423 /**
424  * Create a list output for a member function of this component. A list output
425  * can have multiple values, or channels. The component must publish what channels
426  * its outputs have by calling AbstractOutput::addChannel() within
427  * Component::extendFinalizeFromProperties(). The provided member function must
428  * take the name of the channel whose value is requested.
429  * @code{.cpp}
430  * class MyComponent : public Component {
431  * public:
432  *     double getData(const SimTK::State& s, const std::string& requestedChannel) const;
433  *     OpenSim_DECLARE_LIST_OUTPUT(data, double, getData, SimTK::Stage::Dynamics);
434  *     ...
435  * protected:
436  *     void extendFinalizeFromProperties() {
437  *          Super::extendFinalizeFromProperties();
438  *          for (const auto& name : getChannelsToAdd()) {
439  *              updOutput("data").addChannel(name);
440  *          }
441  *     }
442  * };
443  * @endcode
444  * In this example, `getChannelsToAdd()` is a placeholder for whatever way
445  * you determine your class' available channels. For example, TableSource_
446  * uses the columns of its DataTable_.
447  * @relates OpenSim::Output
448  */
449 #define OpenSim_DECLARE_LIST_OUTPUT(oname, T, func, ostage)                 \
450     /** @name Outputs (list)                                             */ \
451     /** @{                                                               */ \
452     /** Provides the value of func##() and is available at stage ostage. */ \
453     /** This output can have multiple channels. TODO                     */ \
454     /** This output was generated with the                               */ \
455     /** #OpenSim_DECLARE_LIST_OUTPUT macro.                              */ \
456     OpenSim_DOXYGEN_Q_PROPERTY(T, oname)                                    \
457     /** @}                                                               */ \
458     /** @cond                                                            */ \
459     bool _has_output_##oname {                                              \
460         this->template constructListOutput<T>(#oname, &Self::func, ostage)  \
461     };                                                                      \
462     /** @endcond                                                         */
463 
464 // Note: we could omit the T argument from the above macro by using the
465 // following code to deduce T from the provided func
466 //      std::result_of<decltype(&Self::func)(Self, const SimTK::State&)>::type
467 // However, then we wouldn't be able to document the type for the output in
468 // doxygen.
469 
470 /** Create an Output for a StateVariable in this component. The provided
471  * name is both the name of the output and of the state variable.
472  *
473  * While this macro is a convenient way to construct an Output for a
474  * StateVariable, it is inefficient because it uses a string lookup at runtime.
475  * To create a more efficient Output, create a member variable that returns the
476  * state variable directly (see Coordinate::getValue() or
477  * Muscle::getActivation()) and then use the #OpenSim_DECLARE_OUTPUT macro.
478  *
479  * @code{.cpp}
480  * class MyComponent : public Component {
481  * public:
482  *     OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE(activation);
483  *     ...
484  * };
485  * @endcode
486  * @see Component::constructOutputForStateVariable()
487  * @relates OpenSim::Output
488  */
489 #define OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE(oname)                    \
490     /** @name Outputs                                                    */ \
491     /** @{                                                               */ \
492     /** Provides the value of this class's oname state variable.         */ \
493     /** Available at stage SimTK::Stage::Model.                          */ \
494     /** This output was generated with the                               */ \
495     /** #OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE macro.                */ \
496     OpenSim_DOXYGEN_Q_PROPERTY(double, oname)                               \
497     /** @}                                                               */ \
498     /** @cond                                                            */ \
499     bool _has_output_##oname { constructOutputForStateVariable(#oname) };   \
500     /** @endcond                                                         */
501 /// @}
502 //=============================================================================
503 //=============================================================================
504 
505 } // end of namespace OpenSim
506 
507 #endif  // OPENSIM_COMPONENT_OUTPUT_H_
508