1 #ifndef OPENSIM_COMPONENT_H_
2 #define OPENSIM_COMPONENT_H_
3 /* -------------------------------------------------------------------------- *
4 * OpenSim: Component.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 abstract Component class, which is used to add
28 * computational components to the underlying SimTK::System (MultibodySystem).
29 * It specifies the interface that components must satisfy in order to be part
30 * of the system and provides a series of helper methods for adding variables
31 * (state, discrete, cache, ...) to the underlying system. As such,
32 * Component handles all of the bookkeeping for variable indices and
33 * provides convenience access via variable names. Furthermore, a component
34 * embodies constructs of inputs, outputs and connections that are useful in
35 * composing computational systems.
36 *
37 * A component may contain one or more underlying Simbody multibody system
38 * elements (MobilizedBody, Constraint, Force, or Measure) which are part of
39 * a SimTK::Subsystem. A SimTK::Subsystem is where new variables are
40 * allocated. A Component, by default, uses the System's DefaultSubsystem.
41 * for allocating new variables.
42 */
43
44 // INCLUDES
45 #include <OpenSim/Common/osimCommonDLL.h>
46 #include "OpenSim/Common/Object.h"
47 #include "OpenSim/Common/ComponentSocket.h"
48 #include "OpenSim/Common/ComponentOutput.h"
49 #include "OpenSim/Common/Array.h"
50 #include "ComponentList.h"
51 #include "ComponentPath.h"
52 #include <functional>
53
54 #include "simbody/internal/MultibodySystem.h"
55
56 namespace OpenSim {
57
58 class Model;
59 class ModelDisplayHints;
60
61 //==============================================================================
62 /// Component Exceptions
63 //==============================================================================
64 class ComponentHasNoName : public Exception {
65 public:
ComponentHasNoName(const std::string & file,size_t line,const std::string & func,const std::string & componentConcreteClassName)66 ComponentHasNoName(const std::string& file,
67 size_t line,
68 const std::string& func,
69 const std::string& componentConcreteClassName) :
70 Exception(file, line, func) {
71 std::string msg = componentConcreteClassName;
72 msg += " was constructed with no name.\n";
73 msg += "Please assign a valid name and try again.";
74 addMessage(msg);
75 }
76 };
77
78 class InvalidComponentName : public Exception {
79 public:
InvalidComponentName(const std::string & file,size_t line,const std::string & func,const std::string & thisName,const std::string & invalidChars,const std::string & componentConcreteClassName)80 InvalidComponentName(const std::string& file,
81 size_t line,
82 const std::string& func,
83 const std::string& thisName,
84 const std::string& invalidChars,
85 const std::string& componentConcreteClassName) :
86 Exception(file, line, func) {
87 std::string msg = "Component '" + thisName + "' of type " +
88 componentConcreteClassName + " contains invalid characters of: '" +
89 invalidChars + "'.";
90 addMessage(msg);
91 }
92 };
93
94 class ComponentNotFoundOnSpecifiedPath : public ComponentNotFound {
95 public:
ComponentNotFoundOnSpecifiedPath(const std::string & file,size_t line,const std::string & func,const std::string & toFindName,const std::string & toFindClassName,const std::string & thisName)96 ComponentNotFoundOnSpecifiedPath(const std::string& file,
97 size_t line,
98 const std::string& func,
99 const std::string& toFindName,
100 const std::string& toFindClassName,
101 const std::string& thisName) :
102 ComponentNotFound(file, line, func) {
103 std::string msg = "Component '" + thisName;
104 msg += "' could not find '" + toFindName;
105 msg += "' of type " + toFindClassName + ". ";
106 msg += "Make sure a component exists at this path and that it is of ";
107 msg += "the correct type.";
108 addMessage(msg);
109 }
110 };
111
112 class ComponentIsAnOrphan : public Exception {
113 public:
ComponentIsAnOrphan(const std::string & file,size_t line,const std::string & func,const std::string & thisName,const std::string & componentConcreteClassName)114 ComponentIsAnOrphan(const std::string& file,
115 size_t line,
116 const std::string& func,
117 const std::string& thisName,
118 const std::string& componentConcreteClassName) :
119 Exception(file, line, func) {
120 std::string msg = "Component '" + thisName + "' of type " +
121 componentConcreteClassName + " has no owner and is not the root.\n" +
122 "Verify that finalizeFromProperties() has been invoked on the " +
123 "root Component or that this Component is not a clone, which has " +
124 "not been added to another Component.";
125 addMessage(msg);
126 }
127 };
128
129 class SubcomponentsWithDuplicateName : public Exception {
130 public:
SubcomponentsWithDuplicateName(const std::string & file,size_t line,const std::string & func,const std::string & thisName,const std::string & duplicateName)131 SubcomponentsWithDuplicateName(const std::string& file,
132 size_t line,
133 const std::string& func,
134 const std::string& thisName,
135 const std::string& duplicateName) :
136 Exception(file, line, func) {
137 std::string msg = "Component '" + thisName + "' has subcomponents " +
138 "with duplicate name '" + duplicateName + "'. "
139 "Please supply unique names for immediate subcomponents.";
140 addMessage(msg);
141 }
142 };
143
144 class ComponentIsRootWithNoSubcomponents : public Exception {
145 public:
ComponentIsRootWithNoSubcomponents(const std::string & file,size_t line,const std::string & func,const std::string & thisName,const std::string & componentConcreteClassName)146 ComponentIsRootWithNoSubcomponents(const std::string& file,
147 size_t line,
148 const std::string& func,
149 const std::string& thisName,
150 const std::string& componentConcreteClassName) :
151 Exception(file, line, func) {
152 std::string msg = "Component '" + thisName + "' of type " +
153 componentConcreteClassName + " is the root but has no " +
154 "subcomponents listed.\n" +
155 "Verify that finalizeFromProperties() was called on this "
156 "Component to identify its subcomponents.";
157 addMessage(msg);
158 }
159 };
160
161 class ComponentAlreadyPartOfOwnershipTree : public Exception {
162 public:
ComponentAlreadyPartOfOwnershipTree(const std::string & file,size_t line,const std::string & func,const std::string & compName,const std::string & thisName)163 ComponentAlreadyPartOfOwnershipTree(const std::string& file,
164 size_t line,
165 const std::string& func,
166 const std::string& compName,
167 const std::string& thisName) :
168 Exception(file, line, func) {
169 std::string msg = "Component '" + compName;
170 msg += "' already owned by tree to which '" + thisName;
171 msg += "' belongs. Clone the component to adopt a fresh copy.";
172 addMessage(msg);
173 }
174 };
175
176 class ComponentHasNoSystem : public Exception {
177 public:
ComponentHasNoSystem(const std::string & file,size_t line,const std::string & func,const Object & obj)178 ComponentHasNoSystem(const std::string& file,
179 size_t line,
180 const std::string& func,
181 const Object& obj) :
182 Exception(file, line, func, obj) {
183 std::string msg = "Component has no underlying System.\n";
184 msg += "You must call initSystem() on the top-level Component ";
185 msg += "(i.e. Model) first.";
186 addMessage(msg);
187 }
188 };
189
190 class SocketNotFound : public Exception {
191 public:
SocketNotFound(const std::string & file,size_t line,const std::string & func,const Object & obj,const std::string & socketName)192 SocketNotFound(const std::string& file,
193 size_t line,
194 const std::string& func,
195 const Object& obj,
196 const std::string& socketName) :
197 Exception(file, line, func, obj) {
198 std::string msg = "no Socket '" + socketName;
199 msg += "' found for this Component.";
200 addMessage(msg);
201 }
202 };
203
204 class InputNotFound : public Exception {
205 public:
InputNotFound(const std::string & file,size_t line,const std::string & func,const Object & obj,const std::string & inputName)206 InputNotFound(const std::string& file,
207 size_t line,
208 const std::string& func,
209 const Object& obj,
210 const std::string& inputName) :
211 Exception(file, line, func, obj) {
212 std::string msg = "no Input '" + inputName;
213 msg += "' found for this Component.";
214 addMessage(msg);
215 }
216 };
217
218 class OutputNotFound : public Exception {
219 public:
OutputNotFound(const std::string & file,size_t line,const std::string & func,const Object & obj,const std::string & outputName)220 OutputNotFound(const std::string& file,
221 size_t line,
222 const std::string& func,
223 const Object& obj,
224 const std::string& outputName) :
225 Exception(file, line, func, obj) {
226 std::string msg = "no Output '" + outputName;
227 msg += "' found for this Component.";
228 addMessage(msg);
229 }
230 };
231
232 //==============================================================================
233 // OPENSIM COMPONENT
234 //==============================================================================
235 /**
236 * The abstract Component class defines the interface used to add computational
237 * elements to the underlying SimTK::System (MultibodySystem). It specifies
238 * the interface that components must satisfy in order to be part of the system
239 * and provides a series of helper methods for adding variables
240 * (state, discrete, cache, ...) to the underlying system. As such, Component
241 * handles all of the bookkeeping of system indices and provides convenience
242 * access to variable values (incl. derivatives) via their names as strings.
243 *
244 * ### System and State
245 *
246 * The MultibodySystem and its State are defined by Simbody (ref ...). Briefly,
247 * a System represents the mathematical equations that specify the behavior
248 * of a computational model. The State is a collection of all the variables
249 * that uniquely define the unknowns in the system equations. Consider a single
250 * differential equation as a system, while a single set of variable values that
251 * satisfy the equation is a state of that system. These could be values for
252 * joint coordinates, their speeds, as well other variables that govern
253 * the system dynamics (e.g. muscle activation and fiber-length variables
254 * that dictate muscle force). These variables are called continuous state
255 * variables in Simbody, but are more simply referred to as <em>StateVariables</em>
256 * in OpenSim. Component provides services to define and access its
257 * StateVariables and specify their dynamics (derivatives with respect to time)
258 * that are automatically and simultaneously integrated with the MultibodySystem
259 * dynamics. Common operations to integrate, take the max or min, or to delay a
260 * signal, etc. require internal variables to perform their calculations and
261 * these are also held in the State. Simbody provides the infrastructure to
262 * ensure that calculations are kept up-to-date with the state variable values.
263 *
264 * There are other types of "State" variables such as a flag (or options) that
265 * enables a component to be disabled or for a muscle force to be overridden and
266 * and these are identified as <em>ModelingOptions</em> since they may change
267 * the modeled dynamics of the component. Component provides services
268 * that enable developers of components to define additional ModelingOptions.
269 *
270 * ### Discrete variables
271 *
272 * Often a component requires input from an outside source (precomputed data
273 * from a file, another program, or interaction from a user) in which case these
274 * variables do not have dynamics (differential eqns.) known to the component,
275 * but are necessary to describe the dynamical "state" of the system. An example,
276 * is a throttle component (a "controller" that provides an actuator, e.g. a
277 * motor, with a control signal like a voltage or current) which it gets as direct
278 * input from the user (via a joystick, key press, etc..). The throttle controls
279 * the motor torque output and therefore the behavior of the model. The input by
280 * the user to the throttle the motor (the controls) is necessary to specify the
281 * model dynamics at any instant and therefore are considered part of the State.
282 * In OpenSim they are simply referred to as DiscreteVariables. The Component
283 * provides services to enable developers of components to define and access its
284 * DiscreteVariables.
285 *
286 * ### Cache variables
287 *
288 * Fast and efficient simulations also require computationally expensive
289 * calculations to be performed only when necessary. Often the result of an
290 * expensive calculation can be reused many times over, while the variables it
291 * is dependent on remain fixed. The concept of holding onto these values is
292 * called caching and the variables that hold these values are call
293 * <em>CacheVariables</em>. It is important to note, that cache variables are
294 * not state variables. Cache variables can always be recomputed exactly
295 * from the State. OpenSim uses the Simbody infrastructure to manage cache
296 * variables and their validity. Component provides a simplified interface to
297 * define and access CacheVariables.
298 *
299 * ### Stages
300 *
301 * Many modeling and simulation codes put the onus on users and component
302 * creators to manage the validity of cache variables, which is likely to lead
303 * to undetectable errors where cache values are stale (calculated based on past
304 * state variable values). Simbody, on the other hand, provides a more strict
305 * infrastructure to make it easy to exploit the efficiencies of caching while
306 * reducing the risks of validity errors. To do this, Simbody employs the concept
307 * of computational stages to "realize" (or compute) a model's system to a
308 * particular stage requires cached quantities up to and including the stage to
309 * to computed/specified. Simbody utilizes nine realization stages
310 * (<tt>SimTK::Stage::</tt>)
311 *
312 * -# \c Topology finalize System with "slots" for most variables (above)
313 * -# \c %Model specify modeling choices
314 * -# \c Instance specify modifiable model parameters
315 * -# \c Time compute time dependent quantities
316 * -# \c Position compute position dependent quantities
317 * -# \c Velocity compute velocity dependent quantities
318 * -# \c Dynamics compute system applied forces and dependent quantities
319 * -# \c Acceleration compute system accelerations and all other derivatives
320 * -# \c Report compute quantities for reporting/output
321 *
322 * The Component interface is automatically invoked by the System and its
323 * realizations. Component users and most developers need not concern themselves
324 * with \c Topology, \c %Model or \c Instance stages. That interaction is managed
325 * by Component when component creators implement extendAddToSystem() and use the
326 * services provided by Component. Component creators do need to determine and
327 * specify stage dependencies for Discrete and CacheVariables that they add to
328 * their components. For example, the throttle controller reads its value from
329 * user input and it is valid for all calculations as long as time does not
330 * change. If the simulation (via numerical integration) steps forward (or
331 * backward for a trial step) and updates the state, the control from a previous
332 * state (time) should be invalid and an error generated for trying to access
333 * the DiscreteVariable for the control value. To do this one specifies the
334 * "invalidates" stage (e.g. <tt>SimTK::Stage::Time</tt>) for a DiscreteVariable
335 * when the variable is added to the Component. A subsequent change to that
336 * variable will invalidate all state cache entries at that stage or higher. For
337 * example, if a DiscreteVariable is declared to invalidate <tt>Stage::Position</tt>
338 * then changing it will invalidate cache entries that depend on positions,
339 * velocities, forces, and accelerations.
340 *
341 * Similar principles apply to CacheVariables, which requires a "dependsOn" stage to
342 * be specified when a CacheVariable is added to the component. In this case,
343 * the cache variable "shadows" the State (unlike a DiscreteVariable, which is a
344 * part of the State) holding already-computed state-dependent values so that
345 * they do not need to be recomputed until the state changes.
346 * Accessing the CacheVariable in a State whose current stage is lower than
347 * that CacheVariable's specified dependsOn stage will trigger an exception.
348 * It is up to the component to update the value of the cache variable.
349 * Component provides methods to check if the cache is valid, update its value
350 * and then to mark it as valid.
351 *
352 * ### The interface of this class
353 *
354 * The primary responsibility of a Component is to add its computational
355 * representation(s) to the underlying SimTK::System by implementing
356 * extendAddToSystem().
357 *
358 * Additional methods provide support for adding modeling options, state and
359 * cache variables.
360 *
361 * Public methods enable access to component variables via their names.
362 *
363 * ### Subcomponents
364 *
365 * A %Component can have any number of %Components within it; we call these
366 * subcomponents. Subcomponents can also contain their own subcomponents as
367 * well. There are three categories of subcomponents, which vary in whether
368 * they are *configurable* and *fixed in number*:
369 *
370 * - **property subcomponents** Any Property in a Component that is of type
371 * Component is a subcomponent. This includes list properties and Set%s. This
372 * is the most common category of subcomponent, and its distinguishing
373 * feature is that these subcomponents are *configurable* by the user of this
374 * component. These subcomponents appear in the XML for this component, and
375 * can be modified in XML or through the API. They are also not fixed in
376 * number; users can add more property subcomponents to an existing
377 * component (though it is possible to enforce a fixed number by using
378 * one-value properties or limiting the size of a list property). The bodies,
379 * joints, forces, etc. in a Model's BodySet, JointSet, ForceSet, etc. are
380 * all examples of property subcomponents. This category of subcomponent is
381 * the most similar to what was available pre-v4.0.
382 * - **member subcomponents** These are *not* configurable by the user of this
383 * Component, and can only be modified by this Component. You can
384 * still access member subcomponents through the API, but only the component
385 * containing the subcomponents can modify them. Any Component class can have
386 * any number of member subcomponents, but this number is *fixed* for every
387 * instance of the component.
388 * - **adopted subcomponents** These are *not* configurable (does not appear in
389 * XML) and *not* fixed in number. For example, a component can decide,
390 * based on other aspects of the model, that it needs to create a new
391 * subcomponent. This can be done using adopted subcomponents.
392 *
393 * Also, any specific Component can end up in any of these three categories.
394 * That is, if you have a MySpecialForce Component, any other Component can
395 * have it as a property subcomponent, a member subcomponent, or as an adopted
396 * subcomponent.
397 *
398 * @author Ajay Seth, Michael Sherman, Chris Dembia
399 */
400 class OSIMCOMMON_API Component : public Object {
401 OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
402
403 protected:
404 //==============================================================================
405 // PROPERTIES
406 //==============================================================================
407
408 OpenSim_DECLARE_LIST_PROPERTY(components, Component,
409 "List of components that this component owns and serializes.");
410
411 public:
412 //==============================================================================
413 // METHODS
414 //==============================================================================
415 /** Default constructor **/
416 Component();
417
418 /** Construct Component from an XML file. **/
419 Component(const std::string& aFileName,
420 bool aUpdateFromXMLNode = true) SWIG_DECLARE_EXCEPTION;
421
422 /** Construct Component from a specific node in an XML document. **/
423 explicit Component(SimTK::Xml::Element& aNode);
424
425 /** Use default copy constructor and assignment operator. */
426 Component(const Component&) = default;
427 Component& operator=(const Component&) = default;
428
429 /** Destructor is virtual to allow concrete Component to cleanup. **/
430 virtual ~Component() = default;
431
432 /** @name Component Structural Interface
433 The structural interface ensures that deserialization, resolution of
434 inter-connections, and handling of dependencies are performed systematically
435 and prior to system creation, followed by allocation of necessary System
436 resources. These methods can be extended by virtual methods that form the
437 Component Extension Interface (e.g. #extendFinalizeFromProperties)
438 that can be implemented by subclasses of Components.
439
440 Component ensures that the corresponding calls are propagated to all of its
441 subcomponents.*/
442
443 ///@{
444
445 /** Define a Component's internal data members and structure according to
446 its properties. This includes its subcomponents as part of the component
447 ownership tree and identifies its owner (if present) in the tree.
448 finalizeFromProperties propagates to all of the component's subcomponents
449 prior to invoking the virtual extendFinalizeFromProperties() on itself.
450 Note that if the Component has already been added to a System (result of
451 addToSystem(); e.g., Model::initSystem()) when finalizeFromProperties()
452 is called, then finalizeFromProperties() disassociates the component from
453 that System.*/
454 void finalizeFromProperties();
455
456 /** Satisfy the Component's connections specified by its Sockets and Inputs.
457 Locate Components and their Outputs to satisfy the connections in an
458 aggregate Component (e.g. Model), which is the root of a tree of
459 Components. */
460 void finalizeConnections(Component& root);
461
462 /** Disconnect/clear this Component from its aggregate component. Empties
463 all component's sockets and sets them as disconnected.*/
464 void clearConnections();
465
466 /** Have the Component add itself to the underlying computational System */
467 void addToSystem(SimTK::MultibodySystem& system) const;
468
469 /** Initialize Component's state variable values from its properties */
470 void initStateFromProperties(SimTK::State& state) const;
471
472 /** %Set Component's properties given a state. */
473 void setPropertiesFromState(const SimTK::State& state);
474
475 // End of Component Structural Interface (public non-virtual).
476 ///@}
477
478 /** Optional method for generating arbitrary display geometry that reflects
479 this %Component at the specified \a state. This will be called once to
480 obtain ground- and body-fixed geometry (with \a fixed=\c true), and then
481 once per frame (with \a fixed=\c false) to generate on-the-fly geometry such
482 as rubber band lines, force arrows, labels, or debugging aids.
483
484 Please note that there is a precondition that the state passed in to
485 generateDecorations be realized to Stage::Position. If your component can
486 visualize quantities realized at Velocity, Dynamics or Acceleration stages,
487 then you must check that the stage has been realized before using/requesting
488 stage dependent values. It is forbidden to realize the model to a higher
489 stage within generateDecorations, because this can trigger costly side-
490 effects such as evaluating all model forces even when performing a purely
491 kinematic study.
492
493 If you override this method, be sure to invoke the base class method first,
494 using code like this:
495 @code
496 void MyComponent::generateDecorations
497 (bool fixed,
498 const ModelDisplayHints& hints,
499 const SimTK::State& state,
500 SimTK::Array_<SimTK::DecorativeGeometry>& appendToThis) const
501 {
502 // invoke parent class method
503 Super::generateDecorations(fixed,hints,state,appendToThis);
504 // ... your code goes here
505 // can render velocity dependent quanities if stage is Velocity or higher
506 if(state.getSystemStage() >= Stage::Velocity) {
507 // draw velocity vector for model COM
508 }
509 // can render computed forces if stage is Dynamics or higher
510 if(state.getSystemStage() >= Stage::Dynamics) {
511 // change the length of a force arrow based on the force in N
512 }
513 }
514 @endcode
515
516 @param[in] fixed
517 If \c true, generate only geometry that is fixed to a PhysicalFrame,
518 configuration, and velocity. Otherwise generate only such dependent
519 geometry.
520 @param[in] hints
521 See documentation for ModelDisplayHints; you may want to alter the
522 geometry you generate depending on what you find there. For example,
523 you can determine whether the user wants to see debug geometry.
524 @param[in] state
525 The State for which geometry should be produced. See below for more
526 information.
527 @param[in,out] appendToThis
528 %Array to which generated geometry should be \e appended via the
529 \c push_back() method.
530
531 When called with \a fixed=\c true only modeling options and parameters
532 (Instance variables) should affect geometry; time, position, and velocity
533 should not. In that case OpenSim will already have realized the \a state
534 through Instance stage. When called with \a fixed=\c false, you may
535 consult any relevant value in \a state. However, to avoid unnecessary
536 computation, OpenSim guarantees only that \a state will have been realized
537 through Position stage; if you need anything higher than that (reaction
538 forces, for example) you should make sure the \a state is realized through
539 Acceleration stage. **/
generateDecorations(bool fixed,const ModelDisplayHints & hints,const SimTK::State & state,SimTK::Array_<SimTK::DecorativeGeometry> & appendToThis)540 virtual void generateDecorations
541 (bool fixed,
542 const ModelDisplayHints& hints,
543 const SimTK::State& state,
544 SimTK::Array_<SimTK::DecorativeGeometry>& appendToThis) const {};
545
546 /**
547 * Get the underlying MultibodySystem that this component is connected to.
548 * Make sure you have called Model::initSystem() prior to accessing the System.
549 * Throws an Exception if the System has not been created or the Component
550 * has not added itself to the System.
551 * @see hasSystem(). */
552 const SimTK::MultibodySystem& getSystem() const;
553
554 /**
555 * Check if this component has an underlying MultibodySystem.
556 * Returns false if the System has not been created OR if this
557 * Component has not added itself to the System. */
hasSystem()558 bool hasSystem() const { return !_system.empty(); }
559
560 /** Does the provided component already exist anywhere in the ownership
561 * tree (not just subcomponents of this component)? */
562 bool isComponentInOwnershipTree(const Component* component) const;
563
564 /**
565 * Add a Component (as a subcomponent) of this component.
566 * This component takes ownership of the subcomponent and it will be
567 * serialized (appear in XML) as part of this component. Specifically,
568 * it will appear in the `<components>` list for this Component.
569 * If the subcomponent is already owned by this component or exists
570 * in the same hierarchy (tree) as this component, an Exception
571 * is thrown.
572 * @note addComponent is intended to replace existing addBody(), addJoint,
573 * ... on Model or the requirement for specific add###() methods to
574 * subcomponents to a Component.
575 *
576 * Typical usage is:
577 @code
578 // Start with an empty Model (which is a Component)
579 Model myModel;
580 // Create any Component type on the heap
581 Body* newBody = new Body();
582 // Customize the Component by setting its properties
583 newBody->setName("newBody");
584 newBody->setMass(10.0);
585 newBody->setMassCenter(SimTK::Vec3(0));
586 // ...
587 // Now add it to your model, which will take ownership of it
588 myModel.addComponent(newBody);
589 //
590 // Keep creating and adding new components, like Joints, Forces, etc..
591 @endcode
592 *
593 * @throws ComponentAlreadyPartOfOwnershipTree
594 * @param subcomponent is the Component to be added. */
595 void addComponent(Component* subcomponent);
596
597 /**
598 * Get an iterator through the underlying subcomponents that this component is
599 * composed of. The hierarchy of Components/subComponents forms a tree.
600 * The order of the Components is that of tree preorder traversal so that a
601 * component is traversed before its subcomponents.
602 *
603 * @code{.cpp}
604 * for (const auto& muscle : model.getComponentList<Muscle>()) {
605 * muscle.get_max_isometric_force();
606 * }
607 * @endcode
608 *
609 * The returned ComponentList does not permit modifying any components; if
610 * you want to modify the components, see updComponentList().
611 *
612 * @tparam T A subclass of Component (e.g., Body, Muscle).
613 */
614 template <typename T = Component>
getComponentList()615 ComponentList<const T> getComponentList() const {
616 static_assert(std::is_base_of<Component, T>::value,
617 "Template argument must be Component or a derived class.");
618 initComponentTreeTraversal(*this);
619 return ComponentList<const T>(*this);
620 }
621
622 /** Similar to getComponentList(), except the resulting list allows one to
623 modify the components. For example, you could use this method to change
624 the max isometric force of all muscles:
625
626 @code{.cpp}
627 for (auto& muscle : model.updComponentList<Muscle>()) {
628 muscle.set_max_isometric_force(...);
629 }
630 @endcode
631
632 @note Do NOT use this method to add (or remove) (sub)components from any
633 component. The tree structure of the components should not be altered
634 through this ComponentList.
635
636 @tparam T A subclass of Component (e.g., Body, Muscle). */
637 template <typename T = Component>
updComponentList()638 ComponentList<T> updComponentList() {
639 static_assert(std::is_base_of<Component, T>::value,
640 "Template argument must be Component or a derived class.");
641 initComponentTreeTraversal(*this);
642 clearObjectIsUpToDateWithProperties();
643 return ComponentList<T>(*this);
644 }
645
646 /**
647 * Uses getComponentList<T>() to count the number of underlying
648 * subcomponents of the specified type.
649 *
650 * @tparam T A subclass of Component (e.g., Body, Muscle).
651 */
652 template <typename T = Component>
countNumComponents()653 unsigned countNumComponents() const {
654 unsigned count = 0u;
655 const auto compList = getComponentList<T>();
656 auto it = compList.begin();
657 while (it != compList.end()) {
658 ++count;
659 ++it;
660 }
661 return count;
662 }
663
664 /** Class that permits iterating over components/subcomponents (but does
665 * not actually contain the components themselves). */
666 template <typename T>
667 friend class ComponentList;
668 /** Class to iterate over ComponentList returned by getComponentList(). */
669 template <typename T>
670 friend class ComponentListIterator;
671
672
673 /** Get the complete (absolute) pathname for this Component to its ancestral
674 * Component, which is the root of the tree to which this Component belongs.
675 * For example: a Coordinate Component would have an absolute path name
676 * like: `/arm26/elbow_r/flexion`. Accessing a Component by its
677 * absolutePathName from root is guaranteed to be unique. The
678 * absolutePathName is generated on-the-fly by traversing the ownership tree
679 * and, therefore, calling this method is not "free". */
680 std::string getAbsolutePathString() const;
681
682 /** Return a ComponentPath of the absolute path of this Component.
683 * Note that this has more overhead than calling `getName()` because
684 * it traverses up the tree to generate the absolute pathname (and its
685 * computational cost is thus a function of depth). Consider other
686 * options if this is repeatedly called and efficiency is important.
687 * For instance, `getAbsolutePathString()` is faster if you only
688 * need the path as a string. */
689 ComponentPath getAbsolutePath() const;
690
691 /** Get the relative path of this Component with respect to another
692 * Component, as a string. */
693 std::string getRelativePathString(const Component& wrt) const;
694
695 /** Get the relative path of this Component with respect to another
696 * Component. */
697 ComponentPath getRelativePath(const Component& wrt) const;
698
699 /** Query if there is a component (of any type) at the specified
700 * path name. For example,
701 * @code
702 * bool exists = model.hasComponent("right_elbow/elbow_flexion");
703 * @endcode
704 * checks if `model` has a subcomponent "right_elbow," which has a
705 * subcomponent "elbow_flexion." */
hasComponent(const std::string & pathname)706 bool hasComponent(const std::string& pathname) const {
707 return hasComponent<Component>(pathname);
708 }
709
710 /** Query if there is a component of a given type at the specified
711 * path name. For example,
712 * @code
713 * bool exists = model.hasComponent<Coordinate>("right_elbow/elbow_flexion");
714 * @endcode
715 * checks if `model` has a subcomponent "right_elbow," which has a
716 * subcomponent "elbow_flexion," and that "elbow_flexion" is of type
717 * Coordinate. This method cannot be used from scripting; see the
718 * non-templatized hasComponent(). */
719 template <class C = Component>
hasComponent(const std::string & pathname)720 bool hasComponent(const std::string& pathname) const {
721 static_assert(std::is_base_of<Component, C>::value,
722 "Template parameter 'C' must be derived from Component.");
723 const C* comp = this->template traversePathToComponent<C>({pathname});
724 return comp != nullptr;
725 }
726
727 /**
728 * Get a unique subcomponent of this Component by its path name and type 'C'.
729 * Throws ComponentNotFoundOnSpecifiedPath exception if the component at
730 * that path name location does not exist OR it is not of the correct type.
731 * For example,
732 * @code
733 * auto& coord = model.getComponent<Coordinate>("right_elbow/elbow_flexion");
734 * @endcode
735 * returns coord which is a Coordinate named "elbow_flexion" from a Joint
736 * named "right_elbow" given it is a child of the Component (Model) model.
737 * If unsure of a Component's path or whether or not it exists in the model,
738 * use printComponentsMatching() or hasComponent().
739 *
740 * This template function cannot be used in Python/Java/MATLAB; see the
741 * non-templatized getComponent().
742 *
743 * @param pathname a pathname of a Component of interest
744 * @return const reference to component of type C at
745 * @throws ComponentNotFoundOnSpecifiedPath if no component exists
746 */
747 template <class C = Component>
getComponent(const std::string & pathname)748 const C& getComponent(const std::string& pathname) const {
749 return getComponent<C>(ComponentPath(pathname));
750 }
751 template <class C = Component>
getComponent(const ComponentPath & pathname)752 const C& getComponent(const ComponentPath& pathname) const {
753 static_assert(std::is_base_of<Component, C>::value,
754 "Template parameter 'CompType' must be derived from Component.");
755
756 const C* comp = this->template traversePathToComponent<C>(pathname);
757 if (comp) {
758 return *comp;
759 }
760
761 // Only error cases remain
762 OPENSIM_THROW(ComponentNotFoundOnSpecifiedPath, pathname.toString(),
763 C::getClassName(),
764 getName());
765 }
766
767 /** Similar to the templatized getComponent(), except this returns the
768 * component as the generic Component type. This can be used in
769 * Python/Java/MATLAB. Here is an example of using this in MATLAB:
770 * @code
771 * coord = model.getComponent('right_elbow/elbow_flexion')
772 * coord.getNumConnectees() % okay; this is a Component method.
773 * coord.getDefaultClamped() % inaccessible; method on Coordinate.
774 * Coordinate.safeDownCast(coord).getDefaultClamped() % now accessible.
775 * @endcode
776 *
777 * %Exception: in Python, you will get the concrete type (in most cases):
778 * @code{.py}
779 * coord = model.getComponent('right_elbow/elbow_flexion')
780 * coord.getDefaultClamped() # works; no downcasting necessary.
781 * @endcode
782 */
getComponent(const std::string & pathname)783 const Component& getComponent(const std::string& pathname) const {
784 return getComponent<Component>(pathname);
785 }
786
787 /** Get a writable reference to a subcomponent. Use this method
788 * to edit the properties and connections of the subcomponent.
789 * Note: the method will mark this Component as out-of-date with
790 * its properties and will require finalizeFromProperties() to be
791 * invoked directly or indirectly (by finalizeConnections() or
792 * Model::initSystem())
793 * @param name the pathname of the Component of interest
794 * @return Component the component of interest
795 * @throws ComponentNotFoundOnSpecifiedPath if no component exists
796 * @see getComponent()
797 */
798 template <class C = Component>
updComponent(const std::string & name)799 C& updComponent(const std::string& name) {
800 return updComponent<C>(ComponentPath(name));
801 }
802 template <class C = Component>
updComponent(const ComponentPath & name)803 C& updComponent(const ComponentPath& name) {
804 clearObjectIsUpToDateWithProperties();
805 return *const_cast<C*>(&(this->template getComponent<C>(name)));
806 }
807
808 /** Similar to the templatized updComponent(), except this returns the
809 * component as the generic Component type. As with the non-templatized
810 * getComponent(), though, this will give the concrete type in Python in
811 * most cases.
812 * @see getComponent()
813 */
updComponent(const std::string & pathname)814 Component& updComponent(const std::string& pathname) {
815 return updComponent<Component>(pathname);
816 }
817
818
819 /** Print a list to the console of all components whose absolute path name
820 * contains the given string. You might use this if (a) you know the name
821 * of a component in your model but don't know its absolute path, (b) if
822 * you want to find all components with a given name, or (c) to get a list
823 * of all components on the right leg of a model (if all components on the
824 * right side have "_r" in their name).
825 *
826 * A function call like:
827 * @code{.cpp}
828 * unsigned num = comp.printComponentsMatching("rotation");
829 * @endcode
830 * may produce output like:
831 * @verbatim
832 * /leg_model/right_hip/rotation
833 * /leg_model/left_hip/rotation
834 * @endverbatim
835 *
836 * @returns The number of matches. */
837 unsigned printComponentsMatching(const std::string& substring) const;
838
839 /**
840 * Get the number of "continuous" state variables maintained by the
841 * Component and its subcomponents.
842 * @throws ComponentHasNoSystem if this Component has not been added to a
843 * System (i.e., if initSystem has not been called)
844 */
845 int getNumStateVariables() const;
846
847 /**
848 * Get the names of "continuous" state variables maintained by the Component
849 * and its subcomponents.
850 * @throws ComponentHasNoSystem if this Component has not been added to a
851 * System (i.e., if initSystem has not been called)
852 */
853 Array<std::string> getStateVariableNames() const;
854
855
856 /** @name Component Socket Access methods
857 Access Sockets of this component by name. */
858 //@{
859 /** Get the number of Sockets in this Component. */
getNumSockets()860 int getNumSockets() const {
861 return int(_socketsTable.size());
862 }
863
864 /** Collect and return the names of the sockets in this component. You
865 * can use this to iterate through the sockets:
866 * @code
867 * for (std::string name : comp.getSocketNames()) {
868 * const AbstractSocket& socket = getSocket(name);
869 * }
870 * @endcode */
getSocketNames()871 std::vector<std::string> getSocketNames() {
872 std::vector<std::string> names;
873 for (const auto& it : _socketsTable) {
874 names.push_back(it.first);
875 }
876 return names;
877 }
878
879 /**
880 * Get the "connectee" object that the Component's Socket
881 * is bound to. Guaranteed to be valid only after the Component
882 * has been connected (that is connect() has been invoked).
883 * If the Socket has not been connected, an exception is thrown.
884 *
885 * This method is for getting the concrete connectee object, and is not
886 * available in scripting. If you want generic access to the connectee as an
887 * Object, use the non-templated version.
888 *
889 * @tparam T the type of the Connectee (e.g., PhysicalFrame).
890 * @param name the name of the socket
891 * @return T const reference to object that satisfies
892 * the Socket
893 *
894 * Example:
895 * @code
896 * const PhysicalFrame& frame = joint.getConnectee<PhysicalFrame>("parent_frame");
897 * frame.getMobilizedBody();
898 * @endcode
899 */
900 template<typename T>
getConnectee(const std::string & name)901 const T& getConnectee(const std::string& name) const {
902 // get the Socket and check if it is connected.
903 const Socket<T>& socket = getSocket<T>(name);
904 OPENSIM_THROW_IF_FRMOBJ(!socket.isConnected(), Exception,
905 "Socket '" + name + "' not connected.");
906 return socket.getConnectee();
907 }
908
909 /** Get the connectee as an Object. This means you will not have
910 * access to the methods on the concrete connectee. This is the method you
911 * must use in MATLAB to access the connectee.
912 *
913 * Example:
914 * @code{.cpp}
915 * const Object& obj = joint.getConnectee("parent_frame");
916 * obj.getName(); // method on Object works.
917 * obj.getMobilizedBody(); // error: not available.
918 * @endcode
919 *
920 * In MATLAB, if you want the concrete type, you need to downcast the
921 * Object. Here is an example where you know the "parent_frame" is a Body:
922 * @code
923 * f = joint.getConnectee('parent_frame');
924 * m = Body.safeDownCast(f).getMass();
925 * @endcode
926 *
927 * Exception: in Python, you will get the concrete type (in most cases):
928 * @code{.py}
929 * f = joint.getConnectee("parent_frame");
930 * m = f.getMass() # works (if the parent frame is a body)
931 * @endcode
932 */
getConnectee(const std::string & name)933 const Object& getConnectee(const std::string& name) const {
934 const AbstractSocket& socket = getSocket(name);
935 OPENSIM_THROW_IF_FRMOBJ(!socket.isConnected(), Exception,
936 "Socket '" + name + "' not connected.");
937 return socket.getConnecteeAsObject();
938 }
939
940 /** Get an AbstractSocket for the given socket name. This
941 * lets you get information about the connection (like if the socket is
942 * connected), but does not give you access to the socket's connectee.
943 * For that, use getConnectee().
944 *
945 * @internal If you have not yet called finalizeFromProperties() on this
946 * component, this function will update the Socket (to tell it which
947 * component it's in) before providing it to you.
948 *
949 * <b>C++ example</b>
950 * @code{.cpp}
951 * model.getComponent("/path/to/component").getSocket("socketName");
952 * @endcode
953 */
getSocket(const std::string & name)954 const AbstractSocket& getSocket(const std::string& name) const {
955 auto it = _socketsTable.find(name);
956
957 if (it != _socketsTable.end()) {
958 // The following allows one to use a Socket immediately after
959 // copying the component;
960 // e.g., myComponent.clone().getSocket("a").getConnecteePath().
961 // Since we use the default copy constructor for Component,
962 // the copied AbstractSocket cannot know its new owner
963 // immediately after copying.
964 if (!it->second->hasOwner()) {
965 // The `this` pointer must be non-const because the Socket
966 // will want to be able to modify the connectee path property.
967 const_cast<AbstractSocket*>(it->second.get())->setOwner(
968 const_cast<Self&>(*this));
969 }
970 return it->second.getRef();
971 }
972
973 OPENSIM_THROW_FRMOBJ(SocketNotFound, name);
974 }
975
976 /** Get a writable reference to the AbstractSocket for the given
977 * socket name. Use this method to connect the Socket to something.
978 *
979 * <b>C++ example</b>
980 * @code
981 * joint.updSocket("parent_frame").connect(model.getGround());
982 * @endcode
983 *
984 * @internal If you have not yet called finalizeFromProperties() on this
985 * component, this function will update the Socket (to tell it which
986 * component it's in) before providing it to you.
987 */
updSocket(const std::string & name)988 AbstractSocket& updSocket(const std::string& name) {
989 return const_cast<AbstractSocket&>(getSocket(name));
990 }
991
992 /**
993 * Get a const reference to the concrete Socket provided by this
994 * Component by name.
995 *
996 * @internal If you have not yet called finalizeFromProperties() on this
997 * component, this function will update the Socket (to tell it which
998 * component it's in) before providing it to you.
999 *
1000 * @param name the name of the Socket
1001 * @return const reference to the (Abstract)Socket
1002 */
1003 template<typename T>
getSocket(const std::string & name)1004 const Socket<T>& getSocket(const std::string& name) const {
1005 return Socket<T>::downcast(getSocket(name));
1006 }
1007
1008 /**
1009 * Get a writable reference to the concrete Socket provided by this
1010 * Component by name.
1011 *
1012 * @internal If you have not yet called finalizeFromProperties() on this
1013 * component, this function will update the Socket (to tell it which
1014 * component it's in) before providing it to you.
1015 *
1016 * @param name the name of the Socket
1017 * @return const reference to the (Abstract)Socket
1018 */
updSocket(const std::string & name)1019 template<typename T> Socket<T>& updSocket(const std::string& name) {
1020 return const_cast<Socket<T>&>(getSocket<T>(name));
1021 }
1022 //@} end of Component Socket Access methods
1023
1024 /** @name Component Inputs and Outputs Access methods
1025 Access inputs and outputs by name and iterate over all outputs.
1026 */
1027 //@{
1028
1029 /** Access the number of Inputs that this component has. */
getNumInputs()1030 int getNumInputs() const {
1031 return int(_inputsTable.size());
1032 }
1033
1034 /** Access the number of Outputs that this component has. */
getNumOutputs()1035 int getNumOutputs() const {
1036 return int(_outputsTable.size());
1037 }
1038
1039 /** Collect and return the names of Inputs in this component as an
1040 * std::vector. */
getInputNames()1041 std::vector<std::string> getInputNames() const {
1042 std::vector<std::string> names;
1043 for (const auto& it : _inputsTable) {
1044 names.push_back(it.first);
1045 }
1046 return names;
1047 }
1048
1049 /** Collect and return the names of Outputs in this component as an
1050 * std::vector. */
getOutputNames()1051 std::vector<std::string> getOutputNames() const {
1052 std::vector<std::string> names;
1053 for (const auto& entry : getOutputs()) {
1054 names.push_back(entry.first);
1055 }
1056 return names;
1057 }
1058
1059 /**
1060 * Get an Input provided by this Component by name.
1061 *
1062 * <b>C++ example:</b> get an Input from a Component in the model
1063 * @code{.cpp}
1064 * model.getComponent("/path/to/component").getInput("inputName");
1065 * @endcode
1066 *
1067 * @internal If you have not yet called finalizeFromProperties() on this
1068 * component, this function will update the Input (to tell it which
1069 * component it's in) before providing it to you.
1070 *
1071 * @param name the name of the Input
1072 * @return const reference to the AbstractInput
1073 */
getInput(const std::string & name)1074 const AbstractInput& getInput(const std::string& name) const
1075 {
1076 auto it = _inputsTable.find(name);
1077
1078 if (it != _inputsTable.end()) {
1079 // The following allows one to use an Input immediately after
1080 // copying the component;
1081 // e.g., myComponent.clone().getInput("a").getConnecteePath().
1082 // Since we use the default copy constructor for Component,
1083 // the copied AbstractSocket (base class of AbstractInput)
1084 // cannot know its new owner immediately after copying.
1085 if (!it->second->hasOwner()) {
1086
1087 // The `this` pointer must be non-const because the Socket
1088 // will want to be able to modify the connectee_name property.
1089 const_cast<AbstractInput*>(it->second.get())->setOwner(
1090 const_cast<Self&>(*this));
1091 }
1092 return it->second.getRef();
1093 }
1094
1095 OPENSIM_THROW_FRMOBJ(InputNotFound, name);
1096 }
1097
1098 /**
1099 * Get a writable reference to an Input provided by this Component by name.
1100 *
1101 * <b>C++ example:</b> get a writable reference to an Input of a
1102 * Component in a model
1103 * @code{.cpp}
1104 * model.updComponent("/path/to/component").updInput("inputName");
1105 * @endcode
1106 *
1107 * @internal If you have not yet called finalizeFromProperties() on this
1108 * component, this function will update the Input (to tell it which
1109 * component it's in) before providing it to you.
1110
1111 * @param name the name of the Input
1112 * @return reference to the AbstractInput
1113 */
updInput(const std::string & name)1114 AbstractInput& updInput(const std::string& name)
1115 {
1116 return *const_cast<AbstractInput *>(&getInput(name));
1117 }
1118
1119
1120 /**
1121 * Get a concrete Input that you can directly ask for its values.
1122 *
1123 * @internal If you have not yet called finalizeFromProperties() on this
1124 * component, this function will update the Input (to tell it which
1125 * component it's in) before providing it to you.
1126 *
1127 * @param name the name of the Input
1128 * @throws Exception if an Input with the given name does not exist.
1129 * @throws std::bad_cast if the provided type T is incorrect for the given name.
1130 */
1131 template<typename T>
getInput(const std::string & name)1132 const Input<T>& getInput(const std::string& name) const {
1133 return dynamic_cast<const Input<T>&>(getInput(name));
1134 }
1135
1136 /**
1137 * Get the Output provided by this Component by name.
1138 *
1139 * <b>C++ example:</b> get an Output from a Component in a model
1140 * @code{.cpp}
1141 * model.getComponent("/path/to/component").getOutput("outputName");
1142 * @endcode
1143 *
1144 * @param name the name of the Output
1145 * @return const reference to the AbstractOutput
1146 */
getOutput(const std::string & name)1147 const AbstractOutput& getOutput(const std::string& name) const
1148 {
1149 auto it = _outputsTable.find(name);
1150
1151 if (it != _outputsTable.end()) {
1152 return it->second.getRef();
1153 }
1154
1155 OPENSIM_THROW_FRMOBJ(OutputNotFound, name);
1156 }
1157
1158 /**
1159 * Get a writable reference to an Output provided by this Component by name.
1160 *
1161 * <b>C++ example:</b> get a writable reference to an Output of a
1162 * Component in a model
1163 * @code{.cpp}
1164 * model.updComponent("/path/to/component").updOutput("outputName");
1165 * @endcode
1166
1167 * @param name the name of the Output
1168 * @return reference to the AbstractOutput
1169 */
updOutput(const std::string & name)1170 AbstractOutput& updOutput(const std::string& name)
1171 {
1172 return *const_cast<AbstractOutput *>(&getOutput(name));
1173 }
1174
1175 /** Define OutputConstIterator for convenience */
1176 typedef std::map<std::string, SimTK::ClonePtr<AbstractOutput>>::
1177 const_iterator OutputConstIterator;
1178
1179 /** Iterate through all Outputs of this component. The intent is to use
1180 * this in a loop as such:
1181 * @code
1182 * for (const auto& entry : comp.getOutputs()) {
1183 * const std::string& name = entry.first;
1184 * const AbstractOutput* output = entry.second.get();
1185 * std::cout << output->getTypeName() << std::endl;
1186 * }
1187 * @endcode
1188 * This provides access to the outputs as AbstractOutput%s, not as the
1189 * concrete type. This also does not permit modifying the outputs.
1190 *
1191 * Not available in Python/Java/MATLAB; use getOutputNames() and
1192 * getOutput() instead.
1193 */
getOutputs()1194 SimTK::IteratorRange<OutputConstIterator> getOutputs() const {
1195 return {_outputsTable.cbegin(), _outputsTable.cend()};
1196 }
1197 //@} end of Component Inputs and Outputs Access methods
1198
1199
1200
1201 /** @name Component State Access methods
1202 Get and set modeling option, input and output values, state variable,
1203 discrete and/or cache variables in the State.
1204 */
1205 //@{
1206
1207 /**
1208 * Get a ModelingOption flag for this Component by name.
1209 * The flag is an integer corresponding to the index of modelingOptionNames used
1210 * add the modeling option to the component. @see addModelingOption
1211 *
1212 * @param state the State in which to set the modeling option
1213 * @param name the name (string) of the modeling option of interest
1214 * @return flag integer value for modeling option
1215 */
1216 int getModelingOption(const SimTK::State& state, const std::string& name) const;
1217
1218 /**
1219 * %Set the value of a ModelingOption flag for this Component.
1220 * if the integer value exceeds the number of option names used to
1221 * define the options, an exception is thrown. The SimTK::State
1222 * Stage will be reverted back to Stage::Instance.
1223 *
1224 * @param state the State in which to set the flag
1225 * @param name the name (string) of the modeling option of interest
1226 * @param flag the desired flag (int) value specifying the modeling option
1227 */
1228 void setModelingOption(SimTK::State& state, const std::string& name, int flag) const;
1229
1230 /**
1231 * Get the Input value that this component is dependent on.
1232 * Checks if Input is connected, otherwise it will throw an
1233 * exception. You can only call this method for non-list inputs.
1234 * For list inputs, you must get the input using getInput(),
1235 * from which you can ask for its values.
1236 *
1237 * @param state the State for which to set the value
1238 * @param name the name of the input
1239 * @return T const Input value
1240 */
1241 template<typename T> const T&
getInputValue(const SimTK::State & state,const std::string & name)1242 getInputValue(const SimTK::State& state, const std::string& name) const {
1243 // get the input and check if it is connected.
1244 const AbstractInput& in = getInput(name);
1245 // TODO could maybe remove this check and have the Input do it. Or,
1246 // here, we could catch Input's exception and give a different message.
1247 if (in.isConnected()) {
1248 return (Input<T>::downcast(in)).getValue(state);
1249 }
1250
1251 else {
1252 std::stringstream msg;
1253 msg << "Component::getInputValue: ERR- Input '" << name << "' not connected.\n "
1254 << "for component '" << getName() << "' of type "<< getConcreteClassName();
1255 throw Exception(msg.str(), __FILE__, __LINE__);
1256 }
1257 }
1258
1259 /**
1260 * Get the Output value provided by this Component by name.
1261 *
1262 * @param state the State for which to set the value
1263 * @param name the name of the cache variable
1264 * @return T const Output value
1265 */
1266 template<typename T> const T&
getOutputValue(const SimTK::State & state,const std::string & name)1267 getOutputValue(const SimTK::State& state, const std::string& name) const
1268 {
1269 return (Output<T>::downcast(getOutput(name))).getValue(state);
1270 }
1271
1272
1273 /**
1274 * Get the value of a state variable allocated by this Component.
1275 *
1276 * To connect this StateVariable as an input to another component (such as
1277 * a Reporter), use getOutput(name); each state variable has a
1278 * corresponding Output:
1279 * @code
1280 * foo.getInput("input1").connect(bar.getOutput(name));
1281 * @endcode
1282 *
1283 * @param state the State for which to get the value
1284 * @param name the name (string) of the state variable of interest
1285 * @throws ComponentHasNoSystem if this Component has not been added to a
1286 * System (i.e., if initSystem has not been called)
1287 */
1288 double getStateVariableValue(const SimTK::State& state, const std::string& name) const;
1289
1290 /**
1291 * %Set the value of a state variable allocated by this Component by name.
1292 *
1293 * @param state the State for which to set the value
1294 * @param name the name of the state variable
1295 * @param value the value to set
1296 * @throws ComponentHasNoSystem if this Component has not been added to a
1297 * System (i.e., if initSystem has not been called)
1298 */
1299 void setStateVariableValue(SimTK::State& state, const std::string& name, double value) const;
1300
1301
1302 /**
1303 * Get all values of the state variables allocated by this Component.
1304 * Includes state variables allocated by its subcomponents.
1305 *
1306 * @param state the State for which to get the value
1307 * @return Vector of state variable values of length getNumStateVariables()
1308 * in the order returned by getStateVariableNames()
1309 * @throws ComponentHasNoSystem if this Component has not been added to a
1310 * System (i.e., if initSystem has not been called)
1311 */
1312 SimTK::Vector getStateVariableValues(const SimTK::State& state) const;
1313
1314 /**
1315 * %Set all values of the state variables allocated by this Component.
1316 * Includes state variables allocated by its subcomponents. Note, this
1317 * method simply sets the values on the input State. If other conditions
1318 * must be met (such as satisfying kinematic constraints for Coordinates,
1319 * or fiber and tendon equilibrium for muscles) you must invoke the
1320 * appropriate methods on Model (e.g. assemble() to satisfy constraints or
1321 * equilibrateMuscles()) to satisfy these conditions starting from the
1322 * State values provided by setStateVariableValues.
1323 *
1324 * @param state the State whose values are set
1325 * @param values Vector of state variable values of length
1326 * getNumStateVariables() in the order returned by
1327 * getStateVariableNames()
1328 * @throws ComponentHasNoSystem if this Component has not been added to a
1329 * System (i.e., if initSystem has not been called)
1330 */
1331 void setStateVariableValues(SimTK::State& state,
1332 const SimTK::Vector& values) const;
1333
1334 /**
1335 * Get the value of a state variable derivative computed by this Component.
1336 *
1337 * @param state the State for which to get the derivative value
1338 * @param name the name (string) of the state variable of interest
1339 * @throws ComponentHasNoSystem if this Component has not been added to a
1340 * System (i.e., if initSystem has not been called)
1341 */
1342 double getStateVariableDerivativeValue(const SimTK::State& state,
1343 const std::string& name) const;
1344
1345 /**
1346 * Get the value of a discrete variable allocated by this Component by name.
1347 *
1348 * @param state the State from which to get the value
1349 * @param name the name of the state variable
1350 * @return value the discrete variable value
1351 * @throws ComponentHasNoSystem if this Component has not been added to a
1352 * System (i.e., if initSystem has not been called)
1353 */
1354 double getDiscreteVariableValue(const SimTK::State& state,
1355 const std::string& name) const;
1356
1357 /**
1358 * %Set the value of a discrete variable allocated by this Component by name.
1359 *
1360 * @param state the State for which to set the value
1361 * @param name the name of the discrete variable
1362 * @param value the value to set
1363 * @throws ComponentHasNoSystem if this Component has not been added to a
1364 * System (i.e., if initSystem has not been called)
1365 */
1366 void setDiscreteVariableValue(SimTK::State& state, const std::string& name,
1367 double value) const;
1368
1369 /**
1370 * Get the value of a cache variable allocated by this Component by name.
1371 *
1372 * @param state the State from which to get the value
1373 * @param name the name of the cache variable
1374 * @return T const reference to the cache variable's value
1375 * @throws ComponentHasNoSystem if this Component has not been added to a
1376 * System (i.e., if initSystem has not been called)
1377 */
1378 template<typename T> const T&
getCacheVariableValue(const SimTK::State & state,const std::string & name)1379 getCacheVariableValue(const SimTK::State& state, const std::string& name) const
1380 {
1381 // Must have already called initSystem.
1382 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1383
1384 std::map<std::string, CacheInfo>::const_iterator it;
1385 it = _namedCacheVariableInfo.find(name);
1386
1387 if(it != _namedCacheVariableInfo.end()) {
1388 SimTK::CacheEntryIndex ceIndex = it->second.index;
1389 return SimTK::Value<T>::downcast(
1390 getDefaultSubsystem().getCacheEntry(state, ceIndex)).get();
1391 } else {
1392 std::stringstream msg;
1393 msg << "Component::getCacheVariable: ERR- name not found.\n "
1394 << "for component '"<< getName() << "' of type "
1395 << getConcreteClassName();
1396 throw Exception(msg.str(),__FILE__,__LINE__);
1397 }
1398 }
1399 /**
1400 * Obtain a writable cache variable value allocated by this Component by
1401 * name. Do not forget to mark the cache value as valid after updating,
1402 * otherwise it will force a re-evaluation if the evaluation method is
1403 * monitoring the validity of the cache value.
1404 *
1405 * @param state the State for which to set the value
1406 * @param name the name of the state variable
1407 * @return value modifiable reference to the cache variable's value
1408 * @throws ComponentHasNoSystem if this Component has not been added to a
1409 * System (i.e., if initSystem has not been called)
1410 */
1411 template<typename T> T&
updCacheVariableValue(const SimTK::State & state,const std::string & name)1412 updCacheVariableValue(const SimTK::State& state, const std::string& name) const
1413 {
1414 // Must have already called initSystem.
1415 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1416
1417 std::map<std::string, CacheInfo>::const_iterator it;
1418 it = _namedCacheVariableInfo.find(name);
1419
1420 if(it != _namedCacheVariableInfo.end()) {
1421 SimTK::CacheEntryIndex ceIndex = it->second.index;
1422 return SimTK::Value<T>::downcast(
1423 getDefaultSubsystem().updCacheEntry(state, ceIndex)).upd();
1424 }
1425 else{
1426 std::stringstream msg;
1427 msg << "Component::updCacheVariable: ERR- '" << name
1428 << "' name not found.\n "
1429 << "for component '"<< getName() << "' of type "
1430 << getConcreteClassName();
1431 throw Exception(msg.str(),__FILE__,__LINE__);
1432 }
1433 }
1434
1435 /**
1436 * After updating a cache variable value allocated by this Component, you
1437 * can mark its value as valid, which will not change until the realization
1438 * stage falls below the minimum set at the time the cache variable was
1439 * created. If not marked as valid, the evaluation method monitoring this
1440 * flag will force a re-evaluation rather that just reading the value from
1441 * the cache.
1442 *
1443 * @param state the State containing the cache variable
1444 * @param name the name of the cache variable
1445 * @throws ComponentHasNoSystem if this Component has not been added to a
1446 * System (i.e., if initSystem has not been called)
1447 */
markCacheVariableValid(const SimTK::State & state,const std::string & name)1448 void markCacheVariableValid(const SimTK::State& state, const std::string& name) const
1449 {
1450 // Must have already called initSystem.
1451 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1452
1453 std::map<std::string, CacheInfo>::const_iterator it;
1454 it = _namedCacheVariableInfo.find(name);
1455
1456 if(it != _namedCacheVariableInfo.end()) {
1457 SimTK::CacheEntryIndex ceIndex = it->second.index;
1458 getDefaultSubsystem().markCacheValueRealized(state, ceIndex);
1459 }
1460 else{
1461 std::stringstream msg;
1462 msg << "Component::markCacheVariableValid: ERR- name not found.\n "
1463 << "for component '"<< getName() << "' of type "
1464 << getConcreteClassName();
1465 throw Exception(msg.str(),__FILE__,__LINE__);
1466 }
1467 }
1468
1469 /**
1470 * Mark a cache variable value allocated by this Component as invalid. When
1471 * the system realization drops to below the lowest valid stage, cache
1472 * variables are automatically marked as invalid. There are instances when
1473 * component-added state variables require invalidating a cache at a lower
1474 * stage. For example, a component may have a "length" state variable which
1475 * should invalidate calculations involving it and other positions when the
1476 * state variable is set. Changing the component state variable
1477 * automatically invalidates Dynamics and higher realizations, but to force
1478 * realizations at Position and Velocity requires setting the lowest valid
1479 * stage to Position and marking the cache variable as invalid whenever the
1480 * "length" state variable value is set/changed.
1481 *
1482 * @param state the State containing the cache variable
1483 * @param name the name of the cache variable
1484 * @throws ComponentHasNoSystem if this Component has not been added to a
1485 * System (i.e., if initSystem has not been called)
1486 */
markCacheVariableInvalid(const SimTK::State & state,const std::string & name)1487 void markCacheVariableInvalid(const SimTK::State& state,
1488 const std::string& name) const
1489 {
1490 // Must have already called initSystem.
1491 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1492
1493 std::map<std::string, CacheInfo>::const_iterator it;
1494 it = _namedCacheVariableInfo.find(name);
1495
1496 if(it != _namedCacheVariableInfo.end()) {
1497 SimTK::CacheEntryIndex ceIndex = it->second.index;
1498 getDefaultSubsystem().markCacheValueNotRealized(state, ceIndex);
1499 }
1500 else{
1501 std::stringstream msg;
1502 msg << "Component::markCacheVariableInvalid: ERR- name not found.\n"
1503 << "for component '"<< getName() << "' of type "
1504 << getConcreteClassName();
1505 throw Exception(msg.str(),__FILE__,__LINE__);
1506 }
1507 }
1508
1509 /**
1510 * Enables the user to monitor the validity of the cache variable value
1511 * using the returned flag. For components performing a costly evaluation,
1512 * use this method to force a re-evaluation of a cache variable value only
1513 * when necessary (i.e., returns false).
1514 *
1515 * @param state the State in which the cache value resides
1516 * @param name the name of the cache variable
1517 * @return bool whether the cache variable value is valid or not
1518 * @throws ComponentHasNoSystem if this Component has not been added to a
1519 * System (i.e., if initSystem has not been called)
1520 */
isCacheVariableValid(const SimTK::State & state,const std::string & name)1521 bool isCacheVariableValid(const SimTK::State& state, const std::string& name) const
1522 {
1523 // Must have already called initSystem.
1524 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1525
1526 std::map<std::string, CacheInfo>::const_iterator it;
1527 it = _namedCacheVariableInfo.find(name);
1528
1529 if(it != _namedCacheVariableInfo.end()) {
1530 SimTK::CacheEntryIndex ceIndex = it->second.index;
1531 return getDefaultSubsystem().isCacheValueRealized(state, ceIndex);
1532 }
1533 else{
1534 std::stringstream msg;
1535 msg << "Component::isCacheVariableValid: ERR- name not found.\n "
1536 << "for component '"<< getName() << "' of type "
1537 << getConcreteClassName();
1538 throw Exception(msg.str(),__FILE__,__LINE__);
1539 }
1540 }
1541
1542 /**
1543 * %Set cache variable value allocated by this Component by name. All cache
1544 * entries are lazily evaluated (on a need basis) so a set also marks the
1545 * cache as valid.
1546 *
1547 * @param state the State in which to store the new value
1548 * @param name the name of the cache variable
1549 * @param value the new value for this cache variable
1550 * @throws ComponentHasNoSystem if this Component has not been added to a
1551 * System (i.e., if initSystem has not been called)
1552 */
1553 template<typename T> void
setCacheVariableValue(const SimTK::State & state,const std::string & name,const T & value)1554 setCacheVariableValue(const SimTK::State& state, const std::string& name,
1555 const T& value) const
1556 {
1557 // Must have already called initSystem.
1558 OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);
1559
1560 std::map<std::string, CacheInfo>::const_iterator it;
1561 it = _namedCacheVariableInfo.find(name);
1562
1563 if(it != _namedCacheVariableInfo.end()) {
1564 SimTK::CacheEntryIndex ceIndex = it->second.index;
1565 SimTK::Value<T>::downcast(
1566 getDefaultSubsystem().updCacheEntry( state, ceIndex)).upd()
1567 = value;
1568 getDefaultSubsystem().markCacheValueRealized(state, ceIndex);
1569 }
1570 else{
1571 std::stringstream msg;
1572 msg << "Component::setCacheVariable: ERR- name not found.\n "
1573 << "for component '"<< getName() << "' of type "
1574 << getConcreteClassName();
1575 throw Exception(msg.str(),__FILE__,__LINE__);
1576 }
1577 }
1578 // End of Model Component State Accessors.
1579 //@}
1580
1581 /** @name Print information to the console */
1582 /// @{
1583 /** List all subcomponents by name and recurse into these components to
1584 list their subcomponents, and so on. */
1585 void printSubcomponentInfo() const;
1586
1587 /** List all the Sockets of this component and whether or not they are
1588 connected. Also list the connectee paths for sockets that are connected. */
1589 void printSocketInfo() const;
1590
1591 /** List all the inputs of this component and whether or not they are
1592 connected. Also list the (desired) connectee paths for the inputs. */
1593 void printInputInfo() const;
1594
1595 template<typename C>
printSubcomponentInfo()1596 void printSubcomponentInfo() const {
1597
1598 ComponentList<const C> compList = getComponentList<C>();
1599
1600 // Step through compList once to determine if there are any
1601 // subcomponents and to find the longest concrete class name.
1602 const std::string concreteClassName = this->getConcreteClassName();
1603 unsigned numSubcomponents = 0;
1604 size_t maxlen = concreteClassName.length();
1605 for (const C& thisComp : compList) {
1606 ++numSubcomponents;
1607 auto len = thisComp.getConcreteClassName().length();
1608 maxlen = std::max(maxlen, len);
1609 }
1610
1611 if (numSubcomponents == 0) {
1612 std::cout << "Component '" << getName()
1613 << "' has no subcomponents." << std::endl;
1614 return;
1615 }
1616 maxlen += 4; //padding
1617
1618 std::string className = SimTK::NiceTypeName<C>::namestr();
1619 // Remove "OpenSim::", etc. if it exists.
1620 const std::size_t colonPos = className.rfind(":");
1621 if (colonPos != std::string::npos)
1622 className = className.substr(colonPos+1,
1623 className.length()-colonPos);
1624
1625 std::cout << "Class name and absolute path name for descendants of '"
1626 << getName() << "' that are of type " << className << ":\n"
1627 << std::endl;
1628
1629 std::cout << std::string(maxlen-concreteClassName.length(), ' ')
1630 << "[" << concreteClassName << "]"
1631 << " " << getAbsolutePathString() << std::endl;
1632
1633 // Step through compList again to print.
1634 for (const C& thisComp : compList) {
1635 const std::string thisClass = thisComp.getConcreteClassName();
1636 std::cout << std::string(maxlen-thisClass.length(), ' ') << "["
1637 << thisClass << "] ";
1638 auto path = thisComp.getAbsolutePath();
1639 std::cout << std::string((path.getNumPathLevels() - 1) * 4, ' ')
1640 << "/" << path.getComponentName() << std::endl;
1641 }
1642 std::cout << std::endl;
1643 }
1644
1645 /** Print outputs of this component and optionally, those of all
1646 subcomponents. */
1647 void printOutputInfo(const bool includeDescendants = true) const;
1648 /// @}
1649
1650 protected:
1651 class StateVariable;
1652 //template <class T> friend class ComponentSet;
1653 // Give the ComponentMeasure access to the realize() methods.
1654 template <class T> friend class ComponentMeasure;
1655
1656 #ifndef SWIG
1657 /// @class MemberSubcomponentIndex
1658 /// Unique integer type for local member subcomponent indexing
1659 SimTK_DEFINE_UNIQUE_INDEX_TYPE(MemberSubcomponentIndex);
1660
1661 /** Construct a subcomponent as a data member of this Component. All Component
1662 interface calls are automatically invoked on its subcomponents. */
1663 template<class C=Component>
constructSubcomponent(const std::string & name)1664 MemberSubcomponentIndex constructSubcomponent(const std::string& name) {
1665 C* component = new C();
1666 component->setName(name);
1667 component->setOwner(*this);
1668 _memberSubcomponents.push_back(SimTK::ClonePtr<Component>(component));
1669 return MemberSubcomponentIndex(_memberSubcomponents.size()-1);
1670 }
1671 template<class C = Component>
getMemberSubcomponent(MemberSubcomponentIndex ix)1672 const C& getMemberSubcomponent(MemberSubcomponentIndex ix) const {
1673 const C* comp = dynamic_cast<const C*>(_memberSubcomponents[ix].get());
1674 if(comp)
1675 return *comp;
1676
1677 throw Exception("Component::getMemberSubcomponent() - Incorrect type requested.");
1678 }
1679 template<class C = Component>
updMemberSubcomponent(MemberSubcomponentIndex ix)1680 C& updMemberSubcomponent(MemberSubcomponentIndex ix) {
1681 C* comp = dynamic_cast<C*>(_memberSubcomponents[ix].upd());
1682 if (comp)
1683 return *comp;
1684
1685 throw Exception("Component::updMemberSubcomponent() - Incorrect type requested.");
1686 }
1687 #endif //SWIG
1688
1689 /**
1690 * Adopt a component as a subcomponent of this Component. Component
1691 * methods (e.g. addToSystem(), initStateFromProperties(), ...) are
1692 * automatically invoked on subcomponents when called on this Component.
1693 * Realization is also performed automatically on subcomponents. All
1694 * subcomponents are owned, therefore this Component also takes ownership.
1695 */
1696 void adoptSubcomponent(Component* subcomponent);
1697
1698 /** Get the number of Subcomponents immediately owned by this Component */
getNumImmediateSubcomponents()1699 size_t getNumImmediateSubcomponents() const {
1700 return getNumMemberSubcomponents() + getNumPropertySubcomponents()
1701 + getNumAdoptedSubcomponents();
1702 }
1703
1704 /** Get the number of Subcomponents that are data members of this Component */
1705 size_t getNumMemberSubcomponents() const;
1706 /** Get the number of Subcomponents that are properties of this Component */
1707 size_t getNumPropertySubcomponents() const;
1708 /** Get the number of Subcomponents adopted by this Component */
1709 size_t getNumAdoptedSubcomponents() const;
1710
1711 /** Access this Component's immediate subcomponents (not those owned by
1712 subcomponents) */
1713 std::vector<SimTK::ReferencePtr<const Component>>
1714 getImmediateSubcomponents() const;
1715
1716 /** @name Component Extension Interface
1717 The interface ensures that deserialization, resolution of inter-connections,
1718 and handling of dependencies are performed systematically and prior to
1719 system creation, followed by allocation of necessary System resources. These
1720 methods are virtual and may be implemented by subclasses of
1721 Components.
1722
1723 @note Every implementation of virtual extend method xxx(args) must begin
1724 with the line "Super::extend<xxx>(args);" to ensure that the parent class
1725 is called before the child class method.
1726
1727 The base class implementations ensures that the corresponding calls are made
1728 to any subcomponents which are owned by this Component. Ownership is
1729 established by the subcomponent being a data member (not serialized), a
1730 property (serialized), or created and adopted based on other settings
1731 or options that arise from the properties. For example, a Model (Component)
1732 may have to split a body and add a Weld constraint to handle a closed
1733 loop specified by Joints that are properties of the Model. The new Body and
1734 Weld (components) are created and adopted as part of connecting the model to
1735 form a valid multibody tree.
1736
1737 So assuming that your concrete %Component and all intermediate classes from
1738 which it derives properly follow the requirement of calling the Super class
1739 method first, the order of operations enforced here for a call to a single
1740 method will be
1741 -# %Component base class computations
1742 -# calls to that same method for intermediate %Component-derived
1743 objects' computations, in order down from %Component, and
1744 -# call to that method for the bottom-level concrete class.
1745 -# finally calls to that same method for \e all subcomponents
1746 You should consider this ordering when designing a %Component. **/
1747
1748 ///@{
1749
1750 /** Perform any secondary operations, e.g. to investigate the component or
1751 to insert it into a particular internal list (for grouping), after adding
1752 the subcomponent to this component. This is intended primarily for composites
1753 like Model to have more control over the handling of a component being added
1754 to it.
1755
1756 If you override this method, be sure to invoke the base class method first,
1757 using code like this :
1758 @code
1759 void MyComponent::extendAddComponent(Component* subcomponent) {
1760 Super::extendAddComponent(); // invoke parent class method
1761 // ... your code goes here
1762 // ... initialize any internal data structures
1763 }
1764 @endcode */
extendAddComponent(Component * subcomponent)1765 virtual void extendAddComponent(Component* subcomponent) {};
1766
1767 /** Perform any time-invariant calculations, data structure initializations,
1768 or other configuration based on the component's properties to form a
1769 functioning (but not yet connected) component. For example, each property
1770 should be checked to ensure that its value is within an acceptable range.
1771 When this method returns, the component will be marked as being up-to-date
1772 with its properties. Do not perform any configuration that depends on the
1773 SimTK::MultibodySystem; it is not available at this point.
1774
1775 If you override this method, be sure to invoke the base class method first,
1776 using code like this:
1777 @code
1778 void MyComponent::extendFinalizeFromProperties() {
1779 Super::extendFinalizeFromProperties(); // invoke parent class method
1780 // ... your code goes here
1781 // ... catch invalid property values
1782 // ... initialize any internal data structures
1783 }
1784 @endcode */
extendFinalizeFromProperties()1785 virtual void extendFinalizeFromProperties() {};
1786
1787 /** Perform any necessary initializations required to connect the component
1788 (and it subcomponents) to other components and mark the connection status.
1789 Provides a check for error conditions. connect() is invoked on all components
1790 to form a directed acyclic graph of the multibody system, prior to creating the
1791 Simbody MultibodySystem to represent it computationally. It may also be invoked
1792 at times just for its error-checking side effects.
1793
1794 The "root" Component argument is the root node of the directed graph composed
1795 of all the subcomponents (and their subcomponents and so on ...) and their
1796 interconnections. This should yield a fully connected root component. For
1797 ModelComponents this is the Model component. But a Model can be connected to
1798 an environment or world component with several other models, by choosing the
1799 environment/world as the root.
1800
1801 If you override this method, be sure to invoke the base class method first,
1802 using code like this:
1803 @code
1804 void MyComponent::extendFinalizeConnections(Component& root) {
1805 Super::extendFinalizeConnections(root); // invoke parent class method
1806 // ... your code goes here
1807 }
1808 @endcode */
extendFinalizeConnections(Component & root)1809 virtual void extendFinalizeConnections(Component& root) {};
1810
1811 /** Build the tree of Components from this component through its descendants.
1812 This method is invoked whenever a ComponentList<C> is requested. Note that
1813 all components must have been added to the model (or its subcomponents),
1814 otherwise it will not be included in the tree and will not be found for
1815 iteration or for connection. The implementation populates the _nextComponent
1816 ReferencePtr with a pointer to the next Component in tree pre-order traversal.
1817
1818 @throws ComponentIsRootWithNoSubcomponents if the Component is the root and
1819 yet has no subcomponents.
1820 */
1821 void initComponentTreeTraversal(const Component &root) const;
1822
1823 ///@cond
1824 /** Opportunity to remove connection-related information.
1825 If you override this method, be sure to invoke the base class method first,
1826 using code like this:
1827 @code
1828 void MyComponent::disconnect(Component& root) {
1829 // disconnect your subcomponents and your Super first
1830 Super::extendDisconnect();
1831 //your code to wipe out your connection-related information
1832 }
1833 @endcode */
1834 //virtual void extendDisconnect() {};
1835 ///@endcond
1836
1837 /** Add appropriate Simbody elements (if needed) to the System
1838 corresponding to this component and specify needed state resources.
1839 extendAddToSystem() is called when the Simbody System is being created to
1840 represent a completed system (model) for computation. That is, connect()
1841 will already have been invoked on all components before any addToSystem()
1842 call is made. Helper methods for adding modeling options, state variables
1843 and their derivatives, discrete variables, and cache entries are available
1844 and can be called within extendAddToSystem() only.
1845
1846 Note that this method is const; you may not modify your model component
1847 or the containing model during this call. Any modifications you need should
1848 instead be performed in finalizeFromProperties() or at the latest connect(),
1849 which are non-const. The only exception is that you may need to record access
1850 information for resources you create in the \a system, such as an index number.
1851 For most Components, OpenSim base classes either provide convenience methods
1852 or handle indices automatically. Otherwise, you must declare indices as mutable
1853 data members so that you can set them here.
1854
1855 If you override this method, be sure to invoke the base class method at the
1856 beginning, using code like this:
1857 @code
1858 void MyComponent::extendAddToSystem(SimTK::MultibodySystem& system) const {
1859 // Perform any additions to the system required by your Super
1860 Super::extendAddToSystem(system);
1861 // ... your code goes here
1862 }
1863 @endcode
1864
1865 This method assumes that this Component's addToSystem will be invoked before
1866 its subcomponents. If you need your subcomponents to be added to the system,
1867 first (e.g. require of a Force to be anchored to a SimTK::MobilizedBody
1868 specified by subcomponents) then you must implement:
1869 extendAddToSystemAfterSubcomponents().
1870 It is possible to implement both method to add system elements before and then
1871 after your subcomponents have added themselves. Caution is required that
1872 Simbody elements are not added twice especially when order is unimportant.
1873
1874 @param[in,out] system The MultibodySystem being added to.
1875
1876 @see addModelingOption(), addStateVariable(), addDiscreteVariables(),
1877 addCacheVariable() **/
extendAddToSystem(SimTK::MultibodySystem & system)1878 virtual void extendAddToSystem(SimTK::MultibodySystem& system) const {};
1879
1880 /** Add appropriate Simbody elements (if needed) to the System after your
1881 component's subcomponents have had a chance to add themselves to the system.
1882
1883 If you override this method, be sure to invoke the base class method at the
1884 beginning, using code like this:
1885 @code
1886 void MyComponent::
1887 extendAddToSystemAfterSubcomponents(SimTK::MultibodySystem& system) const {
1888 // Perform any additions to the system required by your Super
1889 Super::extendAddToSystemAfterSubcomponents(system);
1890 // ... your code goes here
1891 }
1892 @endcode
1893
1894 @param[in,out] system The MultibodySystem being added to.
1895
1896 @see extendAddToSystem() **/
1897 virtual void
extendAddToSystemAfterSubcomponents(SimTK::MultibodySystem & system)1898 extendAddToSystemAfterSubcomponents(SimTK::MultibodySystem& system)
1899 const {};
1900
1901 /** Transfer property values or other state-independent initial values
1902 into this component's state variables in the passed-in \a state argument.
1903 This is called after a SimTK::System and State have been created for the
1904 Model (that is, after extendAddToSystem() has been called on all components).
1905 You should override this method if your component has properties
1906 (serializable values) that can affect initial values for your state
1907 variables. You can also perform any other state-independent calculations
1908 here that result in state initial conditions.
1909
1910 If you override this method, be sure to invoke the base class method first,
1911 using code like this:
1912 @code
1913 void MyComponent::extendInitStateFromProperties(SimTK::State& state) const {
1914 Super::extendInitStateFromProperties(state); // invoke parent class method
1915 // ... your code goes here
1916 }
1917 @endcode
1918
1919 @param state
1920 The state that will receive the new initial conditions.
1921
1922 @see extendSetPropertiesFromState() **/
extendInitStateFromProperties(SimTK::State & state)1923 virtual void extendInitStateFromProperties(SimTK::State& state) const {};
1924
1925 /** Update this component's property values to match the specified State,
1926 if the component has created any state variable that is intended to
1927 correspond to a property. Thus, state variable values can persist as part
1928 of the model component and be serialized as a property.
1929
1930 If you override this method, be sure to invoke the base class method first,
1931 using code like this:
1932 @code
1933 void MyComponent::extendSetPropertiesFromState(const SimTK::State& state) {
1934 Super::extendSetPropertiesFromState(state); // invoke parent class method
1935 // ... your code goes here
1936 }
1937 @endcode
1938
1939 @param state
1940 The State from which values may be extracted to set persistent
1941 property values.
1942
1943 @see extendInitStateFromProperties() **/
extendSetPropertiesFromState(const SimTK::State & state)1944 virtual void extendSetPropertiesFromState(const SimTK::State& state) {};
1945
1946 /** If a model component has allocated any continuous state variables
1947 using the addStateVariable() method, then %computeStateVariableDerivatives()
1948 must be implemented to provide time derivatives for those states.
1949 Override to set the derivatives of state variables added to the system
1950 by this component. (also see extendAddToSystem()). If the component adds states
1951 and computeStateVariableDerivatives is not implemented by the component,
1952 an exception is thrown when the system tries to evaluate its derivatives.
1953
1954 Implement like this:
1955 @code
1956 void computeStateVariableDerivatives(const SimTK::State& state) const {
1957
1958 // Let the parent class set the derivative values for the
1959 // the state variables that it added.
1960 Super::computeStateVariableDerivatives(state)
1961
1962 // Compute derivative values for states allocated by this component
1963 // as a function of the state.
1964 double deriv = ...
1965
1966 // Then set the derivative value by state variable name
1967 setStateVariableDerivativeValue(state, "<state_variable_name>", deriv);
1968 }
1969 @endcode
1970
1971 For subclasses, it is highly recommended that you first call
1972 Super::computeStateVariableDerivatives(state) to preserve the derivative
1973 computation of the parent class and to only specify the derivatives of the state
1974 variables added by name. One does have the option to override all the derivative
1975 values for the parent by accessing the derivatives by their state variable name.
1976 This is necessary, for example, if a newly added state variable is coupled to the
1977 dynamics (derivatives) of the states variables that were added by the parent.
1978 **/
1979 virtual void computeStateVariableDerivatives(const SimTK::State& s) const;
1980
1981 /**
1982 * %Set the derivative of a state variable by name when computed inside of
1983 * this Component's computeStateVariableDerivatives() method.
1984 *
1985 * @param state the State for which to set the value
1986 * @param name the name of the state variable
1987 * @param deriv the derivative value to set
1988 */
1989 void setStateVariableDerivativeValue(const SimTK::State& state,
1990 const std::string& name, double deriv) const;
1991
1992
1993 // End of Component Extension Interface (protected virtuals).
1994 ///@}
1995
1996 /** @name Component Advanced Interface
1997 You probably won't need to override methods in this section. These provide
1998 a way for you to perform computations ("realizations") that must be
1999 scheduled in carefully-ordered stages as described in the class description
2000 above. The typical operation will be that the given SimTK::State provides
2001 you with the inputs you need for your computation, which you will then
2002 write into some element of the state cache, where later computations can
2003 pick it up.
2004
2005 @note Once again it is crucial that, if you override a method here,
2006 you invoke the superclass method as the <em>first line</em> in your
2007 implementation, via a call like "Super::extendRealizePosition(state);". This
2008 will ensure that all necessary base class computations are performed, and
2009 that subcomponents are handled properly.
2010
2011 @warning Currently the realize() methods here are invoked early in the
2012 sequence of realizations at a given stage, meaning that you will not be
2013 able to access other computations at that same stage.
2014 @bug Should defer calls to these until at least kinematic realizations
2015 at the same stage have been performed.
2016
2017 @see Simbody documentation for more information about realization.
2018 **/
2019 //@{
2020 /** Obtain state resources that are needed unconditionally, and perform
2021 computations that depend only on the system topology. **/
2022 virtual void extendRealizeTopology(SimTK::State& state) const;
2023 /** Obtain and name state resources (like state variables allocated by
2024 an underlying Simbody component) that may be needed, depending on modeling
2025 options. Also, perform any computations that depend only on topology and
2026 selected modeling options. **/
2027 virtual void extendRealizeModel(SimTK::State& state) const;
2028 /** Perform computations that depend only on instance variables, like
2029 lengths and masses. **/
2030 virtual void extendRealizeInstance(const SimTK::State& state) const;
2031 /** Perform computations that depend only on time and earlier stages. **/
2032 virtual void extendRealizeTime(const SimTK::State& state) const;
2033 /** Perform computations that depend only on position-level state
2034 variables and computations performed in earlier stages (including time). **/
2035 virtual void extendRealizePosition(const SimTK::State& state) const;
2036 /** Perform computations that depend only on velocity-level state
2037 variables and computations performed in earlier stages (including position,
2038 and time). **/
2039 virtual void extendRealizeVelocity(const SimTK::State& state) const;
2040 /** Perform computations (typically forces) that may depend on
2041 dynamics-stage state variables, and on computations performed in earlier
2042 stages (including velocity, position, and time), but not on other forces,
2043 accelerations, constraint multipliers, or reaction forces. **/
2044 virtual void extendRealizeDynamics(const SimTK::State& state) const;
2045 /** Perform computations that may depend on applied forces. **/
2046 virtual void extendRealizeAcceleration(const SimTK::State& state) const;
2047 /** Perform computations that may depend on anything but are only used
2048 for reporting and cannot affect subsequent simulation behavior. **/
2049 virtual void extendRealizeReport(const SimTK::State& state) const;
2050 //@} end of Component Advanced Interface
2051
2052
2053 /** @name Component System Creation and Access Methods
2054 * These methods support implementing concrete Components. Add methods
2055 * can only be called inside of extendAddToSystem() and are useful for creating
2056 * the underlying SimTK::System level variables that are used for computing
2057 * values of interest.
2058 * @warning Accessors for System indices are intended for component internal use only.
2059 **/
2060
2061 //@{
2062
2063 /** Add a modeling option (integer flag stored in the State) for use by
2064 this Component. Each modeling option is identified by its own
2065 \a optionName, specified here. Modeling options enable the model
2066 component to be configured differently in order to represent different
2067 operating modes. For example, if two modes of operation are necessary (mode
2068 off and mode on) then specify optionName, "mode" with maxFlagValue = 1.
2069 Subsequent gets will return 0 or 1 and set will only accept 0 and 1 as
2070 acceptable values. Changing the value of a model option invalidates
2071 Stage::Instance and above in the State, meaning all calculations involving
2072 time, positions, velocity, and forces are invalidated. **/
2073 void addModelingOption(const std::string& optionName,
2074 int maxFlagValue) const;
2075
2076
2077 /** Add a continuous system state variable belonging to this Component,
2078 and assign a name by which to refer to it. Changing the value of this state
2079 variable will automatically invalidate everything at and above its
2080 \a invalidatesStage, which is normally Stage::Dynamics meaning that there
2081 are forces that depend on this variable. If you define one or more
2082 of these variables you must also override computeStateVariableDerivatives()
2083 to provide time derivatives for them. Note, all corresponding system
2084 indices are automatically determined using this interface. As an advanced
2085 option you may choose to hide the state variable from being accessed outside
2086 of this component, in which case it is considered to be "hidden".
2087 You may also want to create an Output for this state variable; see
2088 #OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE for more information. Reporters
2089 should use such an Output to get the StateVariable's value (instead of using
2090 getStateVariableValue()).
2091
2092 @param[in] stateVariableName string value to access variable by name
2093 @param[in] invalidatesStage the system realization stage that is
2094 invalidated when variable value is changed
2095 @param[in] isHidden flag (bool) to optionally hide this state
2096 variable from being accessed outside this
2097 component as an Output
2098 */
2099 void addStateVariable(const std::string& stateVariableName,
2100 const SimTK::Stage& invalidatesStage=SimTK::Stage::Dynamics,
2101 bool isHidden = false) const;
2102
2103 /** The above method provides a convenient interface to this method, which
2104 automatically creates an 'AddedStateVariable' and allocates resources in the
2105 SimTK::State for this variable. This interface allows the creator to
2106 add/expose state variables that are allocated by underlying Simbody
2107 components and specify how the state variable value is accessed by
2108 implementing a concrete StateVariable and adding it to the component using
2109 this method.
2110 You may also want to create an Output for this state variable; see
2111 #OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE for more information. Reporters
2112 should use such an Output to get the StateVariable's value (instead of
2113 using getStateVariableValue()).
2114 */
2115 void addStateVariable(Component::StateVariable* stateVariable) const;
2116
2117 /** Add a system discrete variable belonging to this Component, give
2118 it a name by which it can be referenced, and declare the lowest Stage that
2119 should be invalidated if this variable's value is changed. **/
2120 void addDiscreteVariable(const std::string& discreteVariableName,
2121 SimTK::Stage invalidatesStage) const;
2122
2123 /** Add a state cache entry belonging to this Component to hold
2124 calculated values that must be automatically invalidated when certain
2125 state values change. Cache entries contain values whose computations depend
2126 on state variables and provide convenience and/or efficiency by holding on
2127 to them in memory (cache) to avoid recomputation. Once the state changes,
2128 the cache values automatically become invalid and has to be
2129 recomputed based on the current state before it can be referenced again.
2130 Any attempt to reference an invalid cache entry results in an exception
2131 being thrown.
2132
2133 Cache entry validity is managed by computation Stage, rather than by
2134 dependence on individual state variables. Changing a variables whose
2135 "invalidates" stage is the same or lower as the one specified as the
2136 "depends on" stage here cause the cache entry to be invalidated. For
2137 example, a body's momentum, which is dependent on position and velocity
2138 states, should have Stage::Velocity as its \a dependsOnStage. Then if a
2139 Velocity stage variable or lower (e.g. Position stage) changes, then the
2140 cache is invalidated. But, if a Dynamics stage variable (or above) is
2141 changed, the velocity remains valid so the cache entry does not have to be
2142 recomputed.
2143
2144 @param[in] cacheVariableName
2145 The name you are assigning to this cache entry. Must be unique within
2146 this model component.
2147 @param[in] variablePrototype
2148 An object defining the type of value, and a default value of that type,
2149 to be held in this cache entry. Can be a simple int or an elaborate
2150 class, as long as it has deep copy semantics.
2151 @param[in] dependsOnStage
2152 This is the highest computational stage on which this cache entry's
2153 value computation depends. State changes at this level or lower will
2154 invalidate the cache entry. **/
2155 template <class T> void
addCacheVariable(const std::string & cacheVariableName,const T & variablePrototype,SimTK::Stage dependsOnStage)2156 addCacheVariable(const std::string& cacheVariableName,
2157 const T& variablePrototype,
2158 SimTK::Stage dependsOnStage) const
2159 {
2160 // Note, cache index is invalid until the actual allocation occurs
2161 // during realizeTopology.
2162 _namedCacheVariableInfo[cacheVariableName] =
2163 CacheInfo(new SimTK::Value<T>(variablePrototype), dependsOnStage);
2164 }
2165
2166
2167 /**
2168 * Get writable reference to the MultibodySystem that this component is
2169 * connected to.
2170 */
2171 SimTK::MultibodySystem& updSystem() const;
2172
2173 /** Get the index of a Component's continuous state variable in the Subsystem for
2174 allocations. This method is intended for derived Components that may need direct
2175 access to its underlying Subsystem.*/
2176 const int getStateIndex(const std::string& name) const;
2177
2178 /**
2179 * Get the System Index of a state variable allocated by this Component.
2180 * Returns an InvalidIndex if no state variable with the name provided is
2181 * found.
2182 * @param stateVariableName the name of the state variable
2183 */
2184 SimTK::SystemYIndex
2185 getStateVariableSystemIndex(const std::string& stateVariableName) const;
2186
2187 /**
2188 * Get the index of a Component's discrete variable in the Subsystem for
2189 * allocations. This method is intended for derived Components that may need
2190 * direct access to its underlying Subsystem.
2191 */
2192 const SimTK::DiscreteVariableIndex
2193 getDiscreteVariableIndex(const std::string& name) const;
2194
2195 /** Get the index of a Component's cache variable in the Subsystem for allocations.
2196 This method is intended for derived Components that may need direct access
2197 to its underlying Subsystem.*/
2198 const SimTK::CacheEntryIndex
2199 getCacheVariableIndex(const std::string& name) const;
2200
2201 // End of System Creation and Access Methods.
2202 //@}
2203
2204 public:
2205
2206 /** Find a Component to which this Component is an ancestor---in other
2207 words, a Component that is directly owned by this Component or is owned
2208 by one of its sub-components, sub-sub-components, etc. The Component can
2209 be found by type (by specifying a template argument) and either path or
2210 name.
2211
2212 Here is an example of searching for a component of any type with the name
2213 'elbow_flexion':
2214 @code{.cpp}
2215 if (const Component* found =
2216 model.findComponent(ComponentPath("elbow_flexion"))) {
2217 std::cout << found.getName() << std::endl;
2218 }
2219 @endcode
2220
2221 Here, we require that 'elbow_flexion' is of type Coordinate.
2222 @code{.cpp}
2223 if (const Coordinate* found =
2224 model.findComponent<Coordinate>(ComponentPath("elbow_flexion"))) {
2225 std::cout << "Coordinate " << found.getName() << std::endl;
2226 }
2227 @endcode
2228
2229 The search can be sped up considerably if the path or even partial path
2230 name is known. For example, "forearm/elbow/elbow_flexion" will find
2231 the Coordinate component of the elbow joint that connects the forearm body
2232 in linear time (linear search for name at each component level). Whereas
2233 supplying "elbow_flexion" requires a tree search. Returns nullptr (None in
2234 Python, empty array in Matlab) if Component of that specified name cannot
2235 be found.
2236
2237 NOTE: If the component name is ambiguous, an exception is thrown. To
2238 disambiguate, more information must be provided, such as the template
2239 argument to specify the type and/or a path rather than just the name. */
2240 template<class C = Component>
findComponent(const ComponentPath & pathToFind)2241 const C* findComponent(const ComponentPath& pathToFind) const {
2242 const std::string name = pathToFind.toString();
2243 std::string msg = getConcreteClassName() + "'" + getName() +
2244 "'::findComponent() ";
2245 if (name.empty()) {
2246 msg += "cannot find a nameless subcomponent.";
2247 throw Exception(msg);
2248 }
2249
2250 ComponentPath thisAbsPath = getAbsolutePath();
2251
2252 const C* found = NULL;
2253 if (thisAbsPath == pathToFind) {
2254 found = dynamic_cast<const C*>(this);
2255 if (found)
2256 return found;
2257 }
2258
2259 std::vector<const C*> foundCs;
2260
2261 std::string subname = pathToFind.getComponentName();
2262 std::string thisName = this->getName();
2263 if (thisName == subname) {
2264 if ( (found = dynamic_cast<const C*>(this)) )
2265 foundCs.push_back(found);
2266 }
2267
2268 ComponentList<const C> compsList = this->template getComponentList<C>();
2269
2270 for (const C& comp : compsList) {
2271 // if a child of this Component, one should not need
2272 // to specify this Component's absolute path name
2273 ComponentPath compAbsPath = comp.getAbsolutePath();
2274 ComponentPath thisAbsPathPlusSubname = getAbsolutePath();
2275 thisAbsPathPlusSubname.pushBack(subname);
2276 if (compAbsPath == thisAbsPathPlusSubname) {
2277 foundCs.push_back(&comp);
2278 break;
2279 }
2280
2281 // otherwise, we just have a type and name match
2282 // which we may need to support for compatibility with older models
2283 // where only names were used (not path or type)
2284 // TODO replace with an exception -aseth
2285 std::string compName = comp.getName();
2286 if (compName == subname) {
2287 foundCs.push_back(&comp);
2288 // TODO Revisit why the exact match isn't found when
2289 // when what appears to be the complete path.
2290 if (comp.getDebugLevel() > 0) {
2291 std::string details = msg + " Found '" + compAbsPath.toString() +
2292 "' as a match for:\n Component '" + name + "' of type " +
2293 comp.getConcreteClassName() + ", but it "
2294 "is not on specified path.\n";
2295 //throw Exception(details, __FILE__, __LINE__);
2296 std::cout << details << std::endl;
2297 }
2298 }
2299 }
2300
2301 if (foundCs.size() == 1) {
2302 //unique type and name match!
2303 return foundCs[0];
2304 }
2305
2306 // Only error cases remain
2307 // too many components of the right type with the same name
2308 if (foundCs.size() > 1) {
2309 msg += "Found multiple '" + name + "'s of type " +
2310 foundCs[0]->getConcreteClassName() + ".";
2311 throw Exception(msg, __FILE__, __LINE__);
2312 }
2313
2314 // Not found
2315 return nullptr;
2316 }
2317
2318 /** Same as findComponent(const ComponentPath&), but accepting a string (a
2319 path or just a name) as input. */
2320 template<class C = Component>
findComponent(const std::string & pathToFind)2321 const C* findComponent(const std::string& pathToFind) const {
2322 return findComponent<C>(ComponentPath(pathToFind));
2323 }
2324
2325 protected:
2326
2327 template<class C>
traversePathToComponent(ComponentPath path)2328 const C* traversePathToComponent(ComponentPath path) const
2329 {
2330 // Get rid of all the ".."'s that are not at the front of the path.
2331 path.trimDotAndDotDotElements();
2332
2333 // Move up either to the root component or just enough to resolve all
2334 // the ".."'s.
2335 size_t iPathEltStart = 0u;
2336 const Component* current = this;
2337 if (path.isAbsolute()) {
2338 current = ¤t->getRoot();
2339 } else {
2340 while (iPathEltStart < path.getNumPathLevels() &&
2341 path.getSubcomponentNameAtLevel(iPathEltStart) == "..") {
2342 // The path sends us up farther than the root.
2343 if (!current->hasOwner()) return nullptr;
2344 current = ¤t->getOwner();
2345 ++iPathEltStart;
2346 }
2347 }
2348
2349 using RefComp = SimTK::ReferencePtr<const Component>;
2350
2351 // Skip over the root component name.
2352 for (size_t i = iPathEltStart; i < path.getNumPathLevels(); ++i) {
2353 // At this depth in the tree, is there a component whose name
2354 // matches the corresponding path element?
2355 const auto& currentPathElement =
2356 path.getSubcomponentNameAtLevel(i);
2357 const auto& currentSubs = current->getImmediateSubcomponents();
2358 const auto it = std::find_if(currentSubs.begin(), currentSubs.end(),
2359 [currentPathElement](const RefComp& sub)
2360 { return sub->getName() == currentPathElement; });
2361 if (it != currentSubs.end())
2362 current = it->get();
2363 else
2364 return nullptr;
2365 }
2366 if (const C* comp = dynamic_cast<const C*>(current))
2367 return comp;
2368 return nullptr;
2369 }
2370
2371 public:
2372 #ifndef SWIG // StateVariable is protected.
2373 /**
2374 * Get a StateVariable anywhere in the Component tree, given a
2375 * StateVariable path. The StateVariable doesn't need to be in a
2376 * subcomponent of this compoonent; it could be located in a different
2377 * branch of the Component tree (in such a case, the specified path might
2378 * begin with "../").
2379 * This returns nullptr if a StateVariable does not exist at the specified
2380 * path or if the path is invalid.
2381 * @throws ComponentHasNoSystem if this Component has not been added to a
2382 * System (i.e., if initSystem has not been called)
2383 */
2384 const StateVariable* traverseToStateVariable(
2385 const std::string& pathName) const;
2386 #endif
2387
2388 /// @name Access to the owning component (advanced).
2389 /// @{
2390 /** Access the owner of this Component.
2391 * An exception is thrown if the %Component has no owner; in this case, the
2392 * component is the root component, or is orphaned.
2393 * @see hasOwner() */
2394 const Component& getOwner() const;
2395
2396 /** (For advanced users) Check if this %Component has an owner.
2397 * A component may not have an owner if it:
2398 * (1) is the root component, or
2399 * (2) has not been added to another component */
2400 bool hasOwner() const;
2401
2402 /** Obtain the root %Component, which is this component if it is orphaned.
2403 */
2404 const Component& getRoot() const;
2405
2406 protected:
2407 /** %Set this %Component's reference to its owning %Component */
2408 void setOwner(const Component& owner);
2409
2410 /// @}
2411
2412 /** @name Internal methods for constructing Sockets, Outputs, Inputs
2413 * To declare Socket%s, Output%s, and Input%s for your component,
2414 * use the following macros within your class declaration (ideally at
2415 * the top near property declarations):
2416 *
2417 * - #OpenSim_DECLARE_SOCKET
2418 * - #OpenSim_DECLARE_OUTPUT
2419 * - #OpenSim_DECLARE_LIST_OUTPUT
2420 * - #OpenSim_DECLARE_OUTPUT_FOR_STATE_VARIABLE
2421 * - #OpenSim_DECLARE_INPUT
2422 * - #OpenSim_DECLARE_LIST_INPUT
2423 *
2424 * The methods below are used in those macros, and you should not use these
2425 * methods yourself.
2426 */
2427 /// @{
2428 /**
2429 * Construct a specialized Socket for this Component's dependence on
2430 * another Component. It serves as a placeholder for the Component and its
2431 * type and enables the Component to automatically traverse its dependencies
2432 * and provide a meaningful message if the provided Component is
2433 * incompatible or non-existent. This function also creates a Property in
2434 * this component to store the connectee path for this socket; the
2435 * propertyComment argument is the comment to use for that Property. */
2436 template <typename T>
constructSocket(const std::string & name,const std::string & propertyComment)2437 PropertyIndex constructSocket(const std::string& name,
2438 const std::string& propertyComment) {
2439 OPENSIM_THROW_IF(_socketsTable.count(name), Exception,
2440 getConcreteClassName() + " already has a socket named '"
2441 + name + "'.");
2442
2443 // This property is accessed / edited by the Socket class. It is
2444 // not easily accessible to users.
2445 // TODO does putting the addProperty here break the ability to
2446 // create a custom-copy-ctor version of all of this?
2447 // TODO property type should be ComponentPath or something like that.
2448 PropertyIndex propIndex = this->template addProperty<std::string>(
2449 "socket_" + name , propertyComment, "");
2450 // We must create the Property first: the Socket needs the property's
2451 // index in order to access the property later on.
2452 _socketsTable[name].reset(
2453 new Socket<T>(name, propIndex, SimTK::Stage::Topology, *this));
2454 return propIndex;
2455 }
2456
2457 #ifndef SWIG // SWIG can't parse the const at the end of the second argument.
2458 /** Construct an output for a member function of the same component.
2459 The following must be true about componentMemberFunction, the function
2460 that returns the output:
2461
2462 -# It is a member function of \a this component.
2463 -# The member function is const.
2464 -# It takes only one input, which is `const SimTK::State&`
2465 -# The function returns the computed quantity *by value* (e.g.,
2466 `double computeQuantity(const SimTK::State&) const`).
2467
2468 You must also provide the stage on which the output depends.
2469
2470 You can ask outputs for their value only after you call
2471 `finalizeFromProperties()`.
2472
2473 @see constructOutputForStateVariable()
2474 */
2475 template <typename T, typename CompType = Component>
2476 bool constructOutput(const std::string& name,
2477 T (CompType::*const memFunc)(const SimTK::State&) const,
2478 const SimTK::Stage& dependsOn = SimTK::Stage::Acceleration) {
2479 // The `const` in `CompType::*const componentMemberFunction` means this
2480 // function can't assign componentMemberFunction to some other function
2481 // pointer. This is unlikely, since that function would have to match
2482 // the same template parameters (T and CompType).
2483 static_assert(std::is_base_of<Component, CompType>::value,
2484 "Template parameter 'CompType' must be derived from Component.");
2485
2486 // This lambda takes a pointer to a component, downcasts it to the
2487 // appropriate derived type, then calls the member function of the
2488 // derived type. Thank you, klshrinidhi!
2489 // TODO right now, the assignment to result within the lambda is
2490 // making a copy! We can fix this using a reference pointer.
2491 auto outputFunc = [memFunc] (const Component* comp,
2492 const SimTK::State& s, const std::string&, T& result) -> void {
2493 result = std::mem_fn(memFunc)(dynamic_cast<const CompType*>(comp), s);
2494 };
2495 return constructOutput<T>(name, outputFunc, dependsOn);
2496 }
2497 /** This variant handles component member functions that return the
2498 * output value by const reference (const T&).
2499 * @warning ONLY use this with member functions that fetch quantities that
2500 * are stored within the passed-in SimTK::State. The function cannot return
2501 * local variables. */
2502 template <typename T, typename CompType = Component>
2503 bool constructOutput(const std::string& name,
2504 const T& (CompType::*const memFunc)(const SimTK::State&) const,
2505 const SimTK::Stage& dependsOn = SimTK::Stage::Acceleration) {
2506 static_assert(std::is_base_of<Component, CompType>::value,
2507 "Template parameter 'CompType' must be derived from Component.");
2508
2509 // This lambda takes a pointer to a component, downcasts it to the
2510 // appropriate derived type, then calls the member function of the
2511 // derived type. Thank you, klshrinidhi!
2512 auto outputFunc = [memFunc] (const Component* comp,
2513 const SimTK::State& s, const std::string&, T& result) -> void {
2514 result = std::mem_fn(memFunc)(dynamic_cast<const CompType*>(comp), s);
2515 };
2516 return constructOutput<T>(name, outputFunc, dependsOn);
2517 }
2518 /** Construct an output that can have multiple channels. You add Channels
2519 to this Output in extendFinalizeFromProperties() using
2520 AbstractOutput::addChannel(). The member function
2521 you provide must take the name of the channel whose value is requested. */
2522 template <typename T, typename CompType>
2523 bool constructListOutput(const std::string& name,
2524 T (CompType::*const memFunc)(const SimTK::State&,
2525 const std::string& channel) const,
2526 const SimTK::Stage& dependsOn = SimTK::Stage::Acceleration) {
2527 // The `const` in `CompType::*const componentMemberFunction` means this
2528 // function can't assign componentMemberFunction to some other function
2529 // pointer. This is unlikely, since that function would have to match
2530 // the same template parameters (T and CompType).
2531 static_assert(std::is_base_of<Component, CompType>::value,
2532 "Template parameter 'CompType' must be derived from Component.");
2533
2534 // This lambda takes a pointer to a component, downcasts it to the
2535 // appropriate derived type, then calls the member function of the
2536 // derived type. Thank you, klshrinidhi!
2537 auto outputFunc = [memFunc] (const Component* comp,
2538 const SimTK::State& s, const std::string& channel, T& result) -> void {
2539 result = std::mem_fn(memFunc)(
2540 dynamic_cast<const CompType*>(comp), s, channel);
2541 };
2542 return constructOutput<T>(name, outputFunc, dependsOn, true);
2543 }
2544 #endif
2545
2546 /** Construct an Output for a StateVariable. While this method is a
2547 * convenient way to construct an Output for a StateVariable, it is
2548 * inefficient because it uses a string lookup. To create a more efficient
2549 * Output, create a member variable that returns the state variable
2550 * directly; see the implementations of Coordinate::getValue() or
2551 * Muscle::getActivation() for examples.
2552 *
2553 * @param name Name of the output, which must be the same as the name of
2554 * the corresponding state variable. */
2555 bool constructOutputForStateVariable(const std::string& name);
2556
2557 /** Construct an Input (socket) for this Component's dependence on an
2558 * Output signal. It is a placeholder for the Output and its type and
2559 * enables the Component to automatically traverse its dependencies and
2560 * provide a meaningful message if the provided Output is incompatible or
2561 * non-existent. This also specifies at what stage the output must be valid
2562 * for the component to consume it as an input. If the Output's
2563 * dependsOnStage is above the Input's requiredAtStage, an Exception is
2564 * thrown because the output cannot satisfy the Input's requirement.
2565 * This function also creates a Property in this component to store the
2566 * connectee paths for this input; the
2567 * propertyComment argument is the comment to use for that Property. */
2568 template <typename T>
2569 PropertyIndex constructInput(const std::string& name, bool isList,
2570 const std::string& propertyComment,
2571 const SimTK::Stage& requiredAtStage = SimTK::Stage::Instance) {
2572
2573 OPENSIM_THROW_IF(_inputsTable.count(name), Exception,
2574 getConcreteClassName() + " already has an input named '"
2575 + name + "'.");
2576
2577 PropertyIndex propIndex;
2578 // This property is accessed / edited by the AbstractSocket class.
2579 // It is not easily accessible to users.
2580 // TODO property type should be OutputPath or ChannelPath.
2581 if (isList) {
2582 propIndex = this->template addListProperty<std::string>(
2583 "input_" + name, propertyComment,
2584 0, std::numeric_limits<int>::max());
2585 } else {
2586 propIndex = this->template addProperty<std::string>(
2587 "input_" + name, propertyComment, "");
2588 }
2589 // We must create the Property first: the Input needs the property's
2590 // index in order to access the property later on.
2591 _inputsTable[name].reset(
2592 new Input<T>(name, propIndex, requiredAtStage, *this));
2593 return propIndex;
2594 }
2595 /// @}
2596
2597 /// For internal use. Update absolute connectee paths in all sockets and
2598 /// inputs in the subcomponent by prepending the absolute path of the
2599 /// subcomponent. To be used when adding subcomponent to another component.
2600 static void prependComponentPathToConnecteePath(Component& subcomponent);
2601
2602 private:
2603
2604 //Mark components that are properties of this Component as subcomponents of
2605 //this Component. This happens automatically upon construction of the
2606 //component. If a Component property is added programmatically, then one must
2607 //also mark it by calling markAsPropertySubcomponent() with that component.
2608 void markPropertiesAsSubcomponents();
2609
2610 // Internal use: mark as a subcomponent, a component that is owned by this
2611 // Component by virtue of being one of its properties.
2612 void markAsPropertySubcomponent(const Component* subcomponent);
2613
2614 /// Invoke finalizeFromProperties() on the (sub)components of this Component.
2615 void componentsFinalizeFromProperties() const;
2616
2617 /// Invoke connect() on the (sub)components of this Component.
2618 void componentsFinalizeConnections(Component& root);
2619
2620 /// Base Component must create underlying resources in computational System.
2621 void baseAddToSystem(SimTK::MultibodySystem& system) const;
2622
2623 /// Invoke addToSystem() on the (sub)components of this Component.
2624 void componentsAddToSystem(SimTK::MultibodySystem& system) const;
2625
2626 /// Invoke initStateFromProperties() on (sub)components of this Component
2627 void componentsInitStateFromProperties(SimTK::State& state) const;
2628
2629 /// Invoke setPropertiesFromState() on (sub)components of this Component
2630 void componentsSetPropertiesFromState(const SimTK::State& state);
2631
2632 /** Used internally to construct outputs. Creating the functions for
2633 outputs is potentially error-prone if the function binds to (or
2634 captures) a pointer to a class. When the component is copied, the
2635 pointer bound to the function is also copied and points to the original
2636 object. This is unlikely to be the intended behavior. For this reason,
2637 this variant of constructOutput should be used with care.
2638 */
2639 template <typename T>
2640 bool constructOutput(const std::string& name,
2641 const std::function<void (const Component*,
2642 const SimTK::State&,
2643 const std::string& channel, T&)> outputFunction,
2644 const SimTK::Stage& dependsOn = SimTK::Stage::Acceleration,
2645 bool isList = false) {
2646
2647 OPENSIM_THROW_IF(_outputsTable.count(name), Exception,
2648 getConcreteClassName() + " already has an output named '"
2649 + name + "'.");
2650
2651 _outputsTable[name].reset(
2652 new Output<T>(name, outputFunction, dependsOn, isList));
2653 return true;
2654 }
2655
2656 // Get the number of continuous states that the Component added to the
2657 // underlying computational system. It includes the number of built-in states
2658 // exposed by this component. It represents the number of state variables
2659 // managed by this Component.
getNumStateVariablesAddedByComponent()2660 int getNumStateVariablesAddedByComponent() const
2661 { return (int)_namedStateVariableInfo.size(); }
2662 Array<std::string> getStateVariableNamesAddedByComponent() const;
2663
getDefaultSubsystem()2664 const SimTK::DefaultSystemSubsystem& getDefaultSubsystem() const
2665 { return getSystem().getDefaultSubsystem(); }
updDefaultSubsystem()2666 SimTK::DefaultSystemSubsystem& updDefaultSubsystem() const
2667 { return updSystem().updDefaultSubsystem(); }
2668
2669 // Clear all modeling options, continuous and discrete state variables,
2670 // and cache variable allocated by this Component
2671 void clearStateAllocations();
2672
2673 // Reset by clearing underlying system indices.
2674 void reset();
2675
2676 void warnBeforePrint() const override;
2677
2678 protected:
2679 //Derived Components must create concrete StateVariables to expose their state
2680 //variables. When exposing state variables allocated by the underlying Simbody
2681 //component (MobilizedBody, Constraint, Force, etc...) use its interface to
2682 //implement the virtual methods below. Otherwise, if the Component is adding its
2683 //own state variables using the addStateVariable() helper, then an
2684 //AddedStateVariable implements the interface and automatically handles state
2685 //variable access.
2686 class StateVariable {
2687 friend void Component::addStateVariable(StateVariable* sv) const;
2688 public:
StateVariable()2689 StateVariable() : name(""), owner(nullptr),
2690 subsysIndex(SimTK::InvalidIndex), varIndex(SimTK::InvalidIndex),
2691 sysYIndex(SimTK::InvalidIndex), hidden(true) {}
2692 explicit StateVariable(const std::string& name, //state var name
2693 const Component& owner, //owning component
2694 SimTK::SubsystemIndex sbsix,//subsystem for allocation
2695 int varIndex, //variable's index in subsystem
2696 bool hide = false) //state variable is hidden or not
name(name)2697 : name(name), owner(&owner),
2698 subsysIndex(sbsix), varIndex(varIndex),
2699 sysYIndex(SimTK::InvalidIndex), hidden(hide) {}
2700
~StateVariable()2701 virtual ~StateVariable() {}
2702
getName()2703 const std::string& getName() const { return name; }
getOwner()2704 const Component& getOwner() const { return *owner; }
2705
getVarIndex()2706 const int& getVarIndex() const { return varIndex; }
2707 // return the index of the subsystem used to make resource allocations
getSubsysIndex()2708 const SimTK::SubsystemIndex& getSubsysIndex() const { return subsysIndex; }
2709 // return the index in the global list of continuous state variables, Y
getSystemYIndex()2710 const SimTK::SystemYIndex& getSystemYIndex() const { return sysYIndex; }
2711
isHidden()2712 bool isHidden() const { return hidden; }
hide()2713 void hide() { hidden = true; }
show()2714 void show() { hidden = false; }
2715
setVarIndex(int index)2716 void setVarIndex(int index) { varIndex = index; }
setSubsystemIndex(const SimTK::SubsystemIndex & sbsysix)2717 void setSubsystemIndex(const SimTK::SubsystemIndex& sbsysix) {
2718 subsysIndex = sbsysix;
2719 }
2720
2721 //Concrete Components implement how the state variable value is evaluated
2722 virtual double getValue(const SimTK::State& state) const = 0;
2723 virtual void setValue(SimTK::State& state, double value) const = 0;
2724 virtual double getDerivative(const SimTK::State& state) const = 0;
2725 // The derivative a state should be a cache entry and thus does not
2726 // change the state
2727 virtual void setDerivative(const SimTK::State& state, double deriv) const = 0;
2728
2729 private:
2730 std::string name;
2731 SimTK::ReferencePtr<const Component> owner;
2732
2733 // Identify which subsystem this state variable belongs to, which should
2734 // be determined and set at creation time
2735 SimTK::SubsystemIndex subsysIndex;
2736 // The local variable index in the subsystem also provided at creation
2737 // (e.g. can be QIndex, UIndex, or Zindex type)
2738 int varIndex;
2739 // Once allocated a state in the system will have a global index
2740 // and that can be stored here as well
2741 SimTK::SystemYIndex sysYIndex;
2742
2743 // flag indicating if state variable is hidden to the outside world
2744 bool hidden;
2745 };
2746
2747 /// Helper method to enable Component makers to specify the order of their
2748 /// subcomponents to be added to the System during addToSystem(). It is
2749 /// highly unlikely that you will need to reorder the subcomponents of your
2750 /// custom component. This ability is primarily intended for Model (and
2751 /// other top-level) components that have the responsibility of creating a
2752 /// valid SimTK::MultibodySystem. MultibodySystem (Simbody) elements such as
2753 /// MobilizedBodies must be added sequentially to form a Multibody tree.
2754 /// SimTK::Constraints and SimTK::Forces must be applied to MobilizedBodies
2755 /// that are already present in the MultibodySystem. The Model component
2756 /// handles this order for you and should handle user-defined Components
2757 /// without any issues. You should rarely need to use this method yourself.
2758 /// If needed, use this method in extendFinalizeConnections() of your
2759 /// Component (or within your extendConnectToModel() for ModelComponents) to
2760 /// set the order of your subcomponents. For example, Model orders
2761 /// subcomponents according to the Multibody tree and adds bodies and joints
2762 /// in order starting from Ground and growing outward. If the subcomponent
2763 /// already appears in the ordered list setting it later in the list has no
2764 /// effect. The list remains unique. NOTE: If you do need to set the order
2765 /// of your subcomponents, you must do so for all your immediate
2766 /// subcomponents, otherwise those components not in the ordered list will
2767 /// not be added to the System.
2768 void setNextSubcomponentInSystem(const Component& sub) const;
2769
2770 /// resetSubcomponentOrder clears this Component's list of ordered
2771 /// subcomponents (but otherwise leaves subcomponents untouched). You can
2772 /// form the ordered list using setNextSubcomponentInSystem() above.
resetSubcomponentOrder()2773 void resetSubcomponentOrder() {
2774 _orderedSubcomponents.clear();
2775 }
2776
2777 /// Handle a change in XML syntax for Sockets.
2778 void updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber)
2779 override;
2780
2781 private:
2782 // Reference to the owning Component of this Component. It is not the
2783 // previous in the tree, but is the Component one level up that owns this
2784 // one.
2785 SimTK::ReferencePtr<const Component> _owner;
2786
2787 // Reference pointer to the successor of the current Component in Pre-order traversal
2788 mutable SimTK::ReferencePtr<const Component> _nextComponent;
2789
2790 // Reference pointer to the system that this component belongs to.
2791 SimTK::ReferencePtr<SimTK::MultibodySystem> _system;
2792
2793 // propertiesTable maintained by Object
2794
2795 // Table of Component's structural Sockets indexed by name.
2796 std::map<std::string, SimTK::ClonePtr<AbstractSocket>> _socketsTable;
2797
2798 // Table of Component's Inputs indexed by name.
2799 std::map<std::string, SimTK::ClonePtr<AbstractInput>> _inputsTable;
2800
2801 // Table of Component's Outputs indexed by name.
2802 std::map<std::string, SimTK::ClonePtr<AbstractOutput> > _outputsTable;
2803
2804 // Underlying SimTK custom measure ComponentMeasure, which implements
2805 // the realizations in the subsystem by calling private concrete methods on
2806 // the Component. Every model component has one of these, allocated
2807 // in its extendAddToSystem() method, and placed in the System's default
2808 // subsystem.
2809 SimTK::ResetOnCopy<SimTK::MeasureIndex> _simTKcomponentIndex;
2810
2811 // list of subcomponents that are contained in this Component's properties
2812 SimTK::ResetOnCopy<SimTK::Array_<SimTK::ReferencePtr<Component>>>
2813 _propertySubcomponents;
2814 // Keep fixed list of data member Components upon construction
2815 SimTK::Array_<SimTK::ClonePtr<Component> > _memberSubcomponents;
2816 // Hold onto adopted components
2817 SimTK::Array_<SimTK::ClonePtr<Component> > _adoptedSubcomponents;
2818
2819 // A flat list of subcomponents (immediate and otherwise) under this
2820 // Component. This list must be populated prior to addToSystem(), and is
2821 // used strictly to specify the order in which addToSystem() is invoked
2822 // on its subcomponents. The order is necessary for the construction
2823 // of Simbody elements (e.g. MobilizedBodies, Constraints, Forces,
2824 // Measures, ...) which cannot be added to the SimTK::MultibodySystem in
2825 // arbitrary order. In the case of MobilizedBodies, for example, the parent
2826 // MobilizedBody must be part of the system before the child can be added.
2827 // OpenSim::Model performs the mapping from User specifications to the
2828 // system order required by the SimTK::MultibodySystem.
2829 // If the Component does not reset the list, it is by default the ownership
2830 // tree order of its subcomponents.
2831 mutable std::vector<SimTK::ReferencePtr<const Component> > _orderedSubcomponents;
2832
2833 // Structure to hold modeling option information. Modeling options are
2834 // integers 0..maxOptionValue. At run time we keep them in a Simbody
2835 // discrete state variable that invalidates Model stage if changed.
2836 struct ModelingOptionInfo {
ModelingOptionInfoModelingOptionInfo2837 ModelingOptionInfo() : maxOptionValue(-1) {}
ModelingOptionInfoModelingOptionInfo2838 explicit ModelingOptionInfo(int maxOptVal)
2839 : maxOptionValue(maxOptVal) {}
2840 // Model
2841 int maxOptionValue;
2842 // System
2843 SimTK::DiscreteVariableIndex index;
2844 };
2845
2846 // Class for handling state variable added (allocated) by this Component
2847 class AddedStateVariable : public StateVariable {
2848 public:
2849 // Constructors
AddedStateVariable()2850 AddedStateVariable() : StateVariable(),
2851 invalidatesStage(SimTK::Stage::Empty) {}
2852
2853 /** Convenience constructor for defining a Component added state variable */
2854 explicit AddedStateVariable(const std::string& name, //state var name
2855 const Component& owner, //owning component
2856 SimTK::Stage invalidatesStage,//stage this variable invalidates
2857 bool hide=false) :
StateVariable(name,owner,SimTK::SubsystemIndex (SimTK::InvalidIndex),SimTK::InvalidIndex,hide)2858 StateVariable(name, owner,
2859 SimTK::SubsystemIndex(SimTK::InvalidIndex),
2860 SimTK::InvalidIndex, hide),
2861 invalidatesStage(SimTK::Stage::Empty) {}
2862
2863 //override virtual methods
2864 double getValue(const SimTK::State& state) const override;
2865 void setValue(SimTK::State& state, double value) const override;
2866
2867 double getDerivative(const SimTK::State& state) const override;
2868 void setDerivative(const SimTK::State& state, double deriv) const override;
2869
2870 private: // DATA
2871 // Changes in state variables trigger recalculation of appropriate cache
2872 // variables by automatically invalidating the realization stage specified
2873 // upon allocation of the state variable.
2874 SimTK::Stage invalidatesStage;
2875 };
2876
2877 // Structure to hold related info about discrete variables
2878 struct StateVariableInfo {
StateVariableInfoStateVariableInfo2879 StateVariableInfo() {}
StateVariableInfoStateVariableInfo2880 explicit StateVariableInfo(Component::StateVariable* sv, int order) :
2881 stateVariable(sv), order(order) {}
2882
2883 // Need empty copy constructor because default compiler generated
2884 // will fail since it cannot copy a unique_ptr!
StateVariableInfoStateVariableInfo2885 StateVariableInfo(const StateVariableInfo&) {}
2886 // Now handle assignment by moving ownership of the unique pointer
2887 StateVariableInfo& operator=(const StateVariableInfo& svi) {
2888 if(this != &svi){
2889 //assignment has to be const but cannot swap const
2890 //want to keep unique pointer to guarantee no multiple reference
2891 //so use const_cast to swap under the covers
2892 StateVariableInfo* mutableSvi = const_cast<StateVariableInfo *>(&svi);
2893 stateVariable.swap(mutableSvi->stateVariable);
2894 }
2895 order = svi.order;
2896 return *this;
2897 }
2898
2899 // State variable
2900 std::unique_ptr<Component::StateVariable> stateVariable;
2901 // order of allocation
2902 int order;
2903 };
2904
2905 // Structure to hold related info about discrete variables
2906 struct DiscreteVariableInfo {
DiscreteVariableInfoDiscreteVariableInfo2907 DiscreteVariableInfo() {}
DiscreteVariableInfoDiscreteVariableInfo2908 explicit DiscreteVariableInfo(SimTK::Stage invalidates)
2909 : invalidatesStage(invalidates) {}
2910 // Model
2911 SimTK::Stage invalidatesStage;
2912 // System
2913 SimTK::DiscreteVariableIndex index;
2914 };
2915
2916 // Structure to hold related info about cache variables
2917 struct CacheInfo {
CacheInfoCacheInfo2918 CacheInfo() {}
CacheInfoCacheInfo2919 CacheInfo(SimTK::AbstractValue* proto,
2920 SimTK::Stage dependsOn)
2921 : prototype(proto), dependsOnStage(dependsOn) {}
2922 // Model
2923 SimTK::ClonePtr<SimTK::AbstractValue> prototype;
2924 SimTK::Stage dependsOnStage;
2925 // System
2926 SimTK::CacheEntryIndex index;
2927 };
2928
2929 // Map names of modeling options for the Component to their underlying
2930 // SimTK indices.
2931 // These are mutable here so they can ONLY be modified in extendAddToSystem().
2932 // This is not an API bug. The purpose of these maps is to automate the
2933 // bookkeeping of component variables (state variables and cache entries) with
2934 // their index in the computational system. The earliest time we have a valid
2935 // index is when we ask the system to allocate the resources and that only
2936 // happens in extendAddToSystem. Furthermore, extendAddToSystem may not
2937 // alter the Component in any way that would affect its behavior- that is
2938 // why it is const!
2939 // The setting of the variable indices is not in the public interface and is
2940 // not polymorphic.
2941
2942 mutable std::map<std::string, ModelingOptionInfo> _namedModelingOptionInfo;
2943 // Map names of continuous state variables of the Component to their
2944 // underlying SimTK indices.
2945 mutable std::map<std::string, StateVariableInfo> _namedStateVariableInfo;
2946 // Map names of discrete variables of the Component to their underlying
2947 // SimTK indices.
2948 mutable std::map<std::string, DiscreteVariableInfo> _namedDiscreteVariableInfo;
2949 // Map names of cache entries of the Component to their individual
2950 // cache information.
2951 mutable std::map<std::string, CacheInfo> _namedCacheVariableInfo;
2952
2953 // Check that the list of _allStateVariables is valid
2954 bool isAllStatesVariablesListValid() const;
2955
2956 // Array of all state variables for fast access during simulation
2957 mutable SimTK::Array_<SimTK::ReferencePtr<const StateVariable> >
2958 _allStateVariables;
2959 // A handle the System associated with the above state variables
2960 mutable SimTK::ReferencePtr<const SimTK::System> _statesAssociatedSystem;
2961
2962 //==============================================================================
2963 }; // END of class Component
2964 //==============================================================================
2965 //==============================================================================
2966
2967 // Implement methods for ComponentListIterator
2968 /// ComponentListIterator<T> pre-increment operator, advances the iterator to
2969 /// the next valid entry.
2970 template <typename T>
2971 ComponentListIterator<T>& ComponentListIterator<T>::operator++() {
2972 if (_node==nullptr)
2973 return *this;
2974 // If _node has children then successor is first child
2975 // move _node to point to it
2976 if (_node->_memberSubcomponents.size() > 0) {
2977 _node = _node->_memberSubcomponents[0].get();
2978 }
2979 else if (_node->_propertySubcomponents.size() > 0) {
2980 _node = _node->_propertySubcomponents[0].get();
2981 }
2982 else if (_node->_adoptedSubcomponents.size() > 0) {
2983 _node = _node->_adoptedSubcomponents[0].get();
2984 }
2985 // If processing a subtree under _root we stop when our successor is the same
2986 // as the successor of _root as this indicates we're leaving the _root's subtree.
2987 else if (_node->_nextComponent.get() == _root->_nextComponent.get())
2988 _node = nullptr;
2989 else // move on to the next component we computed earlier for the full tree
2990 _node = _node->_nextComponent.get();
2991 advanceToNextValidComponent(); // make sure we have a _node of type T after advancing
2992 return *this;
2993 }
2994
2995 /// Internal method to advance iterator to next valid component.
2996 template <typename T>
advanceToNextValidComponent()2997 void ComponentListIterator<T>::advanceToNextValidComponent() {
2998 // Advance _node to next valid (of type T) if needed
2999 // Similar logic to operator++ but applies _filter->isMatch()
3000 while (_node != nullptr && (dynamic_cast<const T*>(_node) == nullptr ||
3001 !_filter.isMatch(*_node) ||
3002 (_node == _root))){
3003 if (_node->_memberSubcomponents.size() > 0) {
3004 _node = _node->_memberSubcomponents[0].get();
3005 }
3006 else if (_node->_propertySubcomponents.size() > 0) {
3007 _node = _node->_propertySubcomponents[0].get();
3008 }
3009 else if (_node->_adoptedSubcomponents.size() > 0) {
3010 _node = _node->_adoptedSubcomponents[0].get();
3011 }
3012 else {
3013 if (_node->_nextComponent.get() == _root->_nextComponent.get()){ // end of subtree under _root
3014 _node = nullptr;
3015 continue;
3016 }
3017 _node = _node->_nextComponent.get();
3018 }
3019 }
3020 return;
3021 }
3022
3023
3024 class ConnecteeNotSpecified : public Exception {
3025 public:
ConnecteeNotSpecified(const std::string & file,size_t line,const std::string & func,const AbstractSocket & socket,const Component & owner)3026 ConnecteeNotSpecified(const std::string& file,
3027 size_t line,
3028 const std::string& func,
3029 const AbstractSocket& socket,
3030 const Component& owner) :
3031 Exception(file, line, func) {
3032 std::string msg = "Connectee for Socket '" + socket.getName() +
3033 "' of type " + socket.getConnecteeTypeName() + " in " +
3034 owner.getConcreteClassName() + " at " +
3035 owner.getAbsolutePathString() + " is unspecified. "
3036 "If this model was built programmatically, perhaps "
3037 "finalizeConnections() was not called before "
3038 "printing.";
3039 addMessage(msg);
3040 }
3041 };
3042
3043 template<class C>
getConnectee()3044 const C& Socket<C>::getConnectee() const {
3045 if (!isConnected()) {
3046 std::string msg = "Socket " + getName() + " of type " +
3047 C::getClassName() + " in " +
3048 getOwner().getAbsolutePathString() + " of type " +
3049 getOwner().getConcreteClassName() + " is not connected.";
3050 OPENSIM_THROW(Exception, msg);
3051 }
3052 return connectee.getRef();
3053 }
3054
3055 template<class C>
findAndConnect(const ComponentPath & connectee)3056 void Socket<C>::findAndConnect(const ComponentPath& connectee) {
3057 const auto* comp =
3058 getOwner().getRoot().template findComponent<C>(connectee);
3059 OPENSIM_THROW_IF(!comp, ComponentNotFound, connectee.toString(),
3060 getConnecteeTypeName(),
3061 getOwner().getAbsolutePathString());
3062 connect(*comp);
3063 }
3064
3065 template<class C>
finalizeConnection(const Component & root)3066 void Socket<C>::finalizeConnection(const Component& root) {
3067
3068 // If the reference to the connectee is set, use that. Otherwise, use the
3069 // connectee path property.
3070 if (isConnected()) {
3071 const auto& comp = *connectee;
3072 const auto& rootOfConnectee = comp.getRoot();
3073 const auto& myRoot = getOwner().getRoot();
3074 OPENSIM_THROW_IF(&myRoot != &rootOfConnectee, Exception,
3075 "Socket<" + getConnecteeTypeName() + "> '" + getName() +
3076 "' in " + getOwner().getConcreteClassName() + " at " +
3077 getOwner().getAbsolutePathString() + " cannot connect to " +
3078 comp.getConcreteClassName() + " at " +
3079 comp.getAbsolutePathString() + ": components do not have the same "
3080 "root component. Did you intend to add '" +
3081 rootOfConnectee.getName() + "' to '" + myRoot.getName() + "'?");
3082
3083 ComponentPath connecteePath = connectee->getRelativePath(getOwner());
3084 // If the relative path starts with ".." then use an absolute path
3085 // instead.
3086 if (connecteePath.getNumPathLevels() > 1 &&
3087 connecteePath.getSubcomponentNameAtLevel(0) == "..")
3088 connecteePath = connectee->getAbsolutePath();
3089 updConnecteePathProp().setValue(0, connecteePath.toString());
3090
3091 } else {
3092 const auto connecteePath = getConnecteePath();
3093 OPENSIM_THROW_IF(connecteePath.empty(), ConnecteeNotSpecified,
3094 *this, getOwner());
3095
3096 ComponentPath path(connecteePath);
3097 const C* comp = nullptr;
3098 if (path.isAbsolute()) {
3099 comp = &root.template getComponent<C>(path);
3100 } else {
3101 comp = &getOwner().template getComponent<C>(path);
3102 }
3103 connectInternal(*comp);
3104 }
3105 }
3106
3107 template<class T>
connect(const AbstractOutput & output,const std::string & alias)3108 void Input<T>::connect(const AbstractOutput& output,
3109 const std::string& alias) {
3110 const auto* outT = dynamic_cast<const Output<T>*>(&output);
3111 if (!outT) {
3112 std::stringstream msg;
3113 msg << "Type mismatch between Input and Output: Input '" << getName()
3114 << "' of type " << getConnecteeTypeName()
3115 << " cannot connect to Output '" << output.getPathName()
3116 << "' of type " << output.getTypeName() << ".";
3117 OPENSIM_THROW(Exception, msg.str());
3118 }
3119
3120 if (!isListSocket() && outT->getChannels().size() > 1) {
3121 OPENSIM_THROW(Exception,
3122 "Non-list input '" + getName() +
3123 "' cannot connect to output '" + output.getPathName() +
3124 " with more than 1 channel");
3125 }
3126
3127 // For a non-list socket, there will only be one channel.
3128 for (const auto& chan : outT->getChannels()) {
3129 registerChannel(chan.second, alias);
3130 }
3131 }
3132
3133 template<class T>
connect(const AbstractChannel & channel,const std::string & alias)3134 void Input<T>::connect(const AbstractChannel& channel,
3135 const std::string& alias) {
3136 registerChannel(channel, alias);
3137 }
3138
3139 template<class T>
finalizeConnection(const Component & root)3140 void Input<T>::finalizeConnection(const Component& root) {
3141
3142 _connectees.clear();
3143 _aliases.clear();
3144 if (!_registeredChannels.empty()) {
3145 clearConnecteePath();
3146 OPENSIM_THROW_IF(!isListSocket() && getChannels().size() > 1,
3147 Exception,
3148 "Cannot connect single-value input to multiple channels.");
3149 for (const auto& reg : _registeredChannels) {
3150 const Output<T>& output = std::get<0>(reg).getRef();
3151 std::string channelName = std::get<1>(reg);
3152 const AbstractChannel& channel = output.getChannel(channelName);
3153 const std::string& alias = std::get<2>(reg);
3154 connectInternal(channel, std::get<2>(reg));
3155 }
3156
3157 int i = -1;
3158 for (const auto& chan : getChannels()) {
3159
3160 const auto& rootOfConnectee =
3161 chan->getOutput().getOwner().getRoot();
3162 const auto& myRoot = getOwner().getRoot();
3163 OPENSIM_THROW_IF(&myRoot != &rootOfConnectee, Exception,
3164 "Input<" + getConnecteeTypeName() + "> '" + getName() +
3165 "' in " + getOwner().getConcreteClassName() + " at " +
3166 getOwner().getAbsolutePathString() + " cannot connect to " +
3167 "Channel " + chan->getPathName() + ": components do not have "
3168 "the same root component. Did you intend to add '" +
3169 rootOfConnectee.getName() + "' to '" + myRoot.getName() + "'?");
3170
3171 ++i;
3172 // Update the connectee path as
3173 // <OwnerPath>/<Output><:Channel><(annotation)>
3174 const auto& outputOwner = chan->getOutput().getOwner();
3175 ComponentPath path = outputOwner.getRelativePath(getOwner());
3176 // If the relative path starts with ".." then use an absolute path
3177 // instead.
3178 if (path.getNumPathLevels() > 1 &&
3179 path.getSubcomponentNameAtLevel(0) == "..")
3180 path = outputOwner.getAbsolutePath();
3181
3182 auto pathStr = composeConnecteePath(path.toString(),
3183 chan->getOutput().getName(),
3184 chan->getOutput().isListOutput()
3185 ?
3186 chan->getChannelName() :
3187 "",
3188 _aliases[i]);
3189
3190 if (isListSocket())
3191 updConnecteePathProp().appendValue(pathStr);
3192 else
3193 updConnecteePathProp().setValue(pathStr);
3194 }
3195 } else {
3196 if (!isListSocket() && getConnecteePath().empty()) return;
3197 std::string compPathStr, outputName, channelName, alias;
3198 for (unsigned ix = 0; ix < getNumConnectees(); ++ix) {
3199 parseConnecteePath(getConnecteePath(ix),
3200 compPathStr, outputName, channelName, alias);
3201 ComponentPath compPath(compPathStr);
3202 const AbstractOutput* output = nullptr;
3203
3204 if (compPath.isAbsolute()) { //absolute path string
3205 if (compPathStr.empty()) {
3206 output = &root.getOutput(outputName);
3207 } else {
3208 output = &root.getComponent(compPathStr).getOutput(
3209 outputName);
3210 }
3211 } else { // relative path string
3212 const Component* comp = nullptr;
3213 if (compPathStr.empty()) {
3214 comp = &getOwner();
3215 } else {
3216 comp = &getOwner().getComponent(compPathStr);
3217 }
3218 // comp should never be null at this point.
3219 OPENSIM_THROW_IF(!comp, Exception, "Internal error: "
3220 "could not find component '" +
3221 compPathStr + ".");
3222 output = &comp->getOutput(outputName);
3223 }
3224 const auto& channel = output->getChannel(channelName);
3225 connectInternal(channel, alias);
3226 }
3227 }
3228 }
3229
3230
3231 } // end of namespace OpenSim
3232
3233 #endif // OPENSIM_COMPONENT_H_
3234
3235