<NME> PathSpring.h
<BEF> #ifndef OPENSIM_PATH_SPRING_H_
#define OPENSIM_PATH_SPRING_H_
/* -------------------------------------------------------------------------- *
 *                            OpenSim:  PathSpring.h                          *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Ajay Seth                                                       *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */


//=============================================================================
// INCLUDES
//=============================================================================
#include "Force.h"

namespace OpenSim {

class GeometryPath;
class ScaleSet;

//=============================================================================
//=============================================================================
/**
 * A class implementing a PathSpring. The path of the PathSpring is
 * determined by a GeometryPath object. A PathSpring is a massless Force
 * element which applies tension along a path connected to bodies and can wrap
 * over surfaces.  The tension is proportional to its stretch beyond its
 * resting length and the amount of dissipation scales with amount of stretch,
 * such that tension = (K*s)*(1+D*ldot) where stretch, s = l-lo for l > lo, and 
 * 0 otherwise. l is the path length of the spring and lo is its rest length.
 * K is the linear stiffness and D is the dissipation factor.
 * When l < lo the spring applies no tension to the bodies and considered
 * to be slack.
 *
 * @author Ajay Seth
 */
class OSIMSIMULATION_API PathSpring : public Force {
OpenSim_DECLARE_CONCRETE_OBJECT(PathSpring, Force);
public:
//=============================================================================
// PROPERTIES
//=============================================================================
    OpenSim_DECLARE_PROPERTY(resting_length, double,
        "The resting length (m) of the PathSpring");
    OpenSim_DECLARE_PROPERTY(stiffness, double,
        "The linear stiffness (N/m) of the PathSpring");
    OpenSim_DECLARE_PROPERTY(dissipation, double,
        "The dissipation factor (s/m) of the PathSpring");
    OpenSim_DECLARE_UNNAMED_PROPERTY(GeometryPath, 
        "The GeometryPath defines the set of points and wrapping surface" 
        "interactions that form the path of action of the PathSpring");

//=============================================================================
// OUTPUTS
//=============================================================================
    OpenSim_DECLARE_OUTPUT(length, double, getLength,
        SimTK::Stage::Position);
    OpenSim_DECLARE_OUTPUT(stretch, double, getStretch,
        SimTK::Stage::Position);
    OpenSim_DECLARE_OUTPUT(lengthening_speed, double, getLengtheningSpeed,
        SimTK::Stage::Velocity);
    OpenSim_DECLARE_OUTPUT(tension, double, getTension,
        SimTK::Stage::Dynamics);

//==============================================================================
// PUBLIC METHODS
//==============================================================================
    
    /** Default constructor */
    PathSpring();

    /** Convenience constructor with PathSpring parameters
     * @param name          name of this %PathSpring Object
     * @param restLength    the spring's resting length
     * @param stiffness     the spring stiffness
     * @param dissipation   the dissipation factor */
    PathSpring(const std::string& name, 
        double restLength, double stiffness, double dissipation);


    // Uses default (compiler-generated) destructor, copy constructor, and copy
    // assignment operator.

    //--------------------------------------------------------------------------
    //  <B> Get and set PathSpring properties </B>
    //--------------------------------------------------------------------------
    // Properties
    /** get/set the resting length */
    double getRestingLength() const 
    {   return get_resting_length(); }
    void setRestingLength(double restingLength);

    /** get/set the stiffness */
    double getStiffness() const 
    {   return get_stiffness(); }
    void setStiffness(double stiffness);

    /** get/set the dissipation factor */
    double getDissipation() const 
    {   return get_dissipation(); }
    void setDissipation(double dissipation);

    /** Access the GeometryPath to update connection points and
        specify wrap objects the path can interact with. */
    const GeometryPath& getGeometryPath() const 
    {   return get_GeometryPath(); }
    GeometryPath& updGeometryPath() 
    {   return upd_GeometryPath(); }

    //--------------------------------------------------------------------------
    //  <B> State dependent values </B>
    //--------------------------------------------------------------------------
    /** get the length of the PathSpring. Accessible at Stage::Position*/
    double getLength(const SimTK::State& s) const;
    /** get the stretch in the PathSpring. The value of the stretch 
        can only be obtained after the system as be realized to Stage::Position*/
    double getStretch(const SimTK::State& s) const;
    /** get the length of the PathSpring. Accessible at Stage::Velocity*/
    double getLengtheningSpeed(const SimTK::State& s) const;
    /** get the tension generated by the PathSpring. The value of the tension 
        can only be obtained after the system as be realized to Stage::Dynamics */
    double getTension(const SimTK::State& s) const;

    //--------------------------------------------------------------------------
    // COMPUTATIONS
    //--------------------------------------------------------------------------
    /** compute the moment-arm of the PathSpring about a coordinate of interest. */
    double computeMomentArm(const SimTK::State& s, Coordinate& aCoord) const;

    //--------------------------------------------------------------------------
    // SCALE
    //--------------------------------------------------------------------------

    /** Adjust the resting length of the path spring after the model has been
        scaled. The `resting_length` property is multiplied by the quotient of
        the current path length and the path length before scaling. */
    void extendPostScale(const SimTK::State& s,
                         const ScaleSet& scaleSet) override;

protected:
    /** Implementation of Force component virtual method */
    void computeForce(const SimTK::State& s, 
                              SimTK::Vector_<SimTK::SpatialVec>& bodyForces, 
                              SimTK::Vector& generalizedForces) const override; 

    /** Implement ModelComponent interface. */
    void extendFinalizeFromProperties() override;

    //Force reporting
    /** 
     * Methods to query a Force for the value actually applied during simulation
     * The names of the quantities (column labels) is returned by this first function
     * getRecordLabels()
     */
    OpenSim::Array<std::string> getRecordLabels() const override {
        OpenSim::Array<std::string> labels("");
        labels.append(getName()+"_tension");
        return labels;
    }
    /**
     * Given SimTK::State object extract all the values necessary to report forces, application location
     * frame, etc. used in conjunction with getRecordLabels and should return same size Array
     */
    OpenSim::Array<double> getRecordValues(const SimTK::State& state) const override {
        OpenSim::Array<double> values(1);
        values.append(getTension(state));
        return values;
    }

private:
    void constructProperties();

//=============================================================================
};  // END of class PathSpring
//=============================================================================
//=============================================================================
} // end of namespace OpenSim

#endif // OPENSIM_PATH_SPRING_H_

<MSG> Merge pull request #1614 from opensim-org/extendFinalizeFromProperties-PathSprings

add checks for valid property values for ClutchedPathSpring and PathSpring classes
<DFF> @@ -82,7 +82,9 @@ public:
 // PUBLIC METHODS
 //==============================================================================
     
-    /** Default constructor */
+    /** Construct a PathSpring with default parameters. Users should note
+    that the default values for resting_length, stiffness, and dissipation
+    are `NaN` so they must be set before simulating. */
     PathSpring();
 
     /** Convenience constructor with PathSpring parameters

{'commit': 'diff --git a/OpenSim/Actuators/ClutchedPathSpring.cpp b/OpenSim/Actuators/ClutchedPathSpring.cpp\nindex c1dddf8f8..55291ad4b 100644\n--- a/OpenSim/Actuators/ClutchedPathSpring.cpp\n+++ b/OpenSim/Actuators/ClutchedPathSpring.cpp\n@@ -122,6 +122,24 @@ void ClutchedPathSpring::setInitialStretch(double stretch0)\n      set_initial_stretch(getStretch(state));\n  }\n  \n+ void ClutchedPathSpring::extendFinalizeFromProperties()\n+ {\n+     Super::extendFinalizeFromProperties();\n+\n+     OPENSIM_THROW_IF_FRMOBJ(\n+         (SimTK::isNaN(get_stiffness()) || get_stiffness() < 0),\n+         InvalidPropertyValue, getProperty_stiffness().getName());\n+     OPENSIM_THROW_IF_FRMOBJ(\n+         (SimTK::isNaN(get_dissipation()) || get_dissipation() < 0),\n+         InvalidPropertyValue, getProperty_dissipation().getName());\n+     OPENSIM_THROW_IF_FRMOBJ(\n+         (SimTK::isNaN(get_relaxation_time_constant()) || get_relaxation_time_constant() < 0),\n+         InvalidPropertyValue, \n+         getProperty_relaxation_time_constant().getName());\n+     OPENSIM_THROW_IF_FRMOBJ(\n+         (SimTK::isNaN(get_initial_stretch()) || get_initial_stretch() < 0),\n+         InvalidPropertyValue, getProperty_initial_stretch().getName());\n+ }\n \n \n \ndiff --git a/OpenSim/Actuators/ClutchedPathSpring.h b/OpenSim/Actuators/ClutchedPathSpring.h\nindex d262a5949..1d8e04697 100644\n--- a/OpenSim/Actuators/ClutchedPathSpring.h\n+++ b/OpenSim/Actuators/ClutchedPathSpring.h\n@@ -78,6 +78,9 @@ public:\n //=============================================================================\n // PUBLIC METHODS\n //=============================================================================\n+    /** Construct a ClutchedPathSpring with default parameters. Users should\n+        note that the default values for stiffness and dissipation are `NaN`\n+        so they must be set before simulating. */\n     ClutchedPathSpring();\n     \n     /** Convenience constructor with ClutchedPathSpring parameters\n@@ -138,6 +141,7 @@ protected:\n     void extendAddToSystem(SimTK::MultibodySystem& system) const override;\n     void extendInitStateFromProperties(SimTK::State& state) const override;\n     void extendSetPropertiesFromState(const SimTK::State& state) override;\n+    void extendFinalizeFromProperties() override;\n     void computeStateVariableDerivatives(const SimTK::State& s) const override;\n \n private:\ndiff --git a/OpenSim/Simulation/Model/PathSpring.cpp b/OpenSim/Simulation/Model/PathSpring.cpp\nindex ad093ad05..edf93fdea 100644\n--- a/OpenSim/Simulation/Model/PathSpring.cpp\n+++ b/OpenSim/Simulation/Model/PathSpring.cpp\n@@ -109,8 +109,15 @@ void PathSpring::extendFinalizeFromProperties()\n     GeometryPath& path = upd_GeometryPath();\n     path.setDefaultColor(DefaultPathSpringColor);\n \n-    // Resting length must be greater than 0.0.\n-    assert(get_resting_length() > 0.0);\n+    OPENSIM_THROW_IF_FRMOBJ(\n+        (SimTK::isNaN(get_resting_length()) || get_resting_length() < 0),\n+        InvalidPropertyValue, getProperty_resting_length().getName());\n+    OPENSIM_THROW_IF_FRMOBJ(\n+        (SimTK::isNaN(get_stiffness()) || get_stiffness() < 0),\n+        InvalidPropertyValue, getProperty_stiffness().getName());\n+    OPENSIM_THROW_IF_FRMOBJ(\n+        (SimTK::isNaN(get_dissipation()) || get_dissipation() < 0),\n+        InvalidPropertyValue, getProperty_dissipation().getName());\n }\n \n \ndiff --git a/OpenSim/Simulation/Model/PathSpring.h b/OpenSim/Simulation/Model/PathSpring.h\nindex 9cddcc2b6..aa5df7490 100644\n--- a/OpenSim/Simulation/Model/PathSpring.h\n+++ b/OpenSim/Simulation/Model/PathSpring.h\n@@ -82,7 +82,9 @@ public:\n // PUBLIC METHODS\n //==============================================================================\n     \n-    /** Default constructor */\n+    /** Construct a PathSpring with default parameters. Users should note\n+    that the default values for resting_length, stiffness, and dissipation\n+    are `NaN` so they must be set before simulating. */\n     PathSpring();\n \n     /** Convenience constructor with PathSpring parameters\n', 'commit_subject': 'Merge pull request #1614 from opensim-org/extendFinalizeFromProperties-PathSprings', 'repo_name': 'opensim-org/opensim-core', 'committer': {'name': 'GitHub', 'email': '1505422b2465e9a84f6fdfaa161078890c593f06@github.com', 'time_sec': '1490568114', 'tz_offset': '-420', 'date': {'seconds': '1490568114'}}, 'commit_tree': '092df3b82c69f5636478c275dbb01c766b0a148b', 'commit_message': 'Merge pull request #1614 from opensim-org/extendFinalizeFromProperties-PathSprings\n\nadd checks for valid property values for ClutchedPathSpring and PathSpring classes', 'language_name': 'C', 'license': 'apache-2.0', 'hunks': '@@ -82,7 +82,9 @@ public:\n // PUBLIC METHODS\n //==============================================================================\n     \n-    /** Default constructor */\n+    /** Construct a PathSpring with default parameters. Users should note\n+    that the default values for resting_length, stiffness, and dissipation\n+    are `NaN` so they must be set before simulating. */\n     PathSpring();\n \n     /** Convenience constructor with PathSpring parameters\n', 'addition_count': 3, 'deletion_count': 1, 'src_file': 'a/OpenSim/Simulation/Model/PathSpring.h', 'tgt_file': 'b/OpenSim/Simulation/Model/PathSpring.h', 'file_extension': '.h', 'before_file': '#ifndef OPENSIM_PATH_SPRING_H_\n#define OPENSIM_PATH_SPRING_H_\n/* -------------------------------------------------------------------------- *\n *                            OpenSim:  PathSpring.h                          *\n * -------------------------------------------------------------------------- *\n * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *\n * See http://opensim.stanford.edu and the NOTICE file for more information.  *\n * OpenSim is developed at Stanford University and supported by the US        *\n * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *\n * through the Warrior Web program.                                           *\n *                                                                            *\n * Copyright (c) 2005-2017 Stanford University and the Authors                *\n * Author(s): Ajay Seth                                                       *\n *                                                                            *\n * Licensed under the Apache License, Version 2.0 (the "License"); you may    *\n * not use this file except in compliance with the License. You may obtain a  *\n * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *\n *                                                                            *\n * Unless required by applicable law or agreed to in writing, software        *\n * distributed under the License is distributed on an "AS IS" BASIS,          *\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *\n * See the License for the specific language governing permissions and        *\n * limitations under the License.                                             *\n * -------------------------------------------------------------------------- */\n\n\n//=============================================================================\n// INCLUDES\n//=============================================================================\n#include "Force.h"\n\nnamespace OpenSim {\n\nclass GeometryPath;\nclass ScaleSet;\n\n//=============================================================================\n//=============================================================================\n/**\n * A class implementing a PathSpring. The path of the PathSpring is\n * determined by a GeometryPath object. A PathSpring is a massless Force\n * element which applies tension along a path connected to bodies and can wrap\n * over surfaces.  The tension is proportional to its stretch beyond its\n * resting length and the amount of dissipation scales with amount of stretch,\n * such that tension = (K*s)*(1+D*ldot) where stretch, s = l-lo for l > lo, and \n * 0 otherwise. l is the path length of the spring and lo is its rest length.\n * K is the linear stiffness and D is the dissipation factor.\n * When l < lo the spring applies no tension to the bodies and considered\n * to be slack.\n *\n * @author Ajay Seth\n */\nclass OSIMSIMULATION_API PathSpring : public Force {\nOpenSim_DECLARE_CONCRETE_OBJECT(PathSpring, Force);\npublic:\n//=============================================================================\n// PROPERTIES\n//=============================================================================\n    OpenSim_DECLARE_PROPERTY(resting_length, double,\n        "The resting length (m) of the PathSpring");\n    OpenSim_DECLARE_PROPERTY(stiffness, double,\n        "The linear stiffness (N/m) of the PathSpring");\n    OpenSim_DECLARE_PROPERTY(dissipation, double,\n        "The dissipation factor (s/m) of the PathSpring");\n    OpenSim_DECLARE_UNNAMED_PROPERTY(GeometryPath, \n        "The GeometryPath defines the set of points and wrapping surface" \n        "interactions that form the path of action of the PathSpring");\n\n//=============================================================================\n// OUTPUTS\n//=============================================================================\n    OpenSim_DECLARE_OUTPUT(length, double, getLength,\n        SimTK::Stage::Position);\n    OpenSim_DECLARE_OUTPUT(stretch, double, getStretch,\n        SimTK::Stage::Position);\n    OpenSim_DECLARE_OUTPUT(lengthening_speed, double, getLengtheningSpeed,\n        SimTK::Stage::Velocity);\n    OpenSim_DECLARE_OUTPUT(tension, double, getTension,\n        SimTK::Stage::Dynamics);\n\n//==============================================================================\n// PUBLIC METHODS\n//==============================================================================\n    \n    /** Default constructor */\n    PathSpring();\n\n    /** Convenience constructor with PathSpring parameters\n     * @param name          name of this %PathSpring Object\n     * @param restLength    the spring\'s resting length\n     * @param stiffness     the spring stiffness\n     * @param dissipation   the dissipation factor */\n    PathSpring(const std::string& name, \n        double restLength, double stiffness, double dissipation);\n\n\n    // Uses default (compiler-generated) destructor, copy constructor, and copy\n    // assignment operator.\n\n    //--------------------------------------------------------------------------\n    //  <B> Get and set PathSpring properties </B>\n    //--------------------------------------------------------------------------\n    // Properties\n    /** get/set the resting length */\n    double getRestingLength() const \n    {   return get_resting_length(); }\n    void setRestingLength(double restingLength);\n\n    /** get/set the stiffness */\n    double getStiffness() const \n    {   return get_stiffness(); }\n    void setStiffness(double stiffness);\n\n    /** get/set the dissipation factor */\n    double getDissipation() const \n    {   return get_dissipation(); }\n    void setDissipation(double dissipation);\n\n    /** Access the GeometryPath to update connection points and\n        specify wrap objects the path can interact with. */\n    const GeometryPath& getGeometryPath() const \n    {   return get_GeometryPath(); }\n    GeometryPath& updGeometryPath() \n    {   return upd_GeometryPath(); }\n\n    //--------------------------------------------------------------------------\n    //  <B> State dependent values </B>\n    //--------------------------------------------------------------------------\n    /** get the length of the PathSpring. Accessible at Stage::Position*/\n    double getLength(const SimTK::State& s) const;\n    /** get the stretch in the PathSpring. The value of the stretch \n        can only be obtained after the system as be realized to Stage::Position*/\n    double getStretch(const SimTK::State& s) const;\n    /** get the length of the PathSpring. Accessible at Stage::Velocity*/\n    double getLengtheningSpeed(const SimTK::State& s) const;\n    /** get the tension generated by the PathSpring. The value of the tension \n        can only be obtained after the system as be realized to Stage::Dynamics */\n    double getTension(const SimTK::State& s) const;\n\n    //--------------------------------------------------------------------------\n    // COMPUTATIONS\n    //--------------------------------------------------------------------------\n    /** compute the moment-arm of the PathSpring about a coordinate of interest. */\n    double computeMomentArm(const SimTK::State& s, Coordinate& aCoord) const;\n\n    //--------------------------------------------------------------------------\n    // SCALE\n    //--------------------------------------------------------------------------\n\n    /** Adjust the resting length of the path spring after the model has been\n        scaled. The `resting_length` property is multiplied by the quotient of\n        the current path length and the path length before scaling. */\n    void extendPostScale(const SimTK::State& s,\n                         const ScaleSet& scaleSet) override;\n\nprotected:\n    /** Implementation of Force component virtual method */\n    void computeForce(const SimTK::State& s, \n                              SimTK::Vector_<SimTK::SpatialVec>& bodyForces, \n                              SimTK::Vector& generalizedForces) const override; \n\n    /** Implement ModelComponent interface. */\n    void extendFinalizeFromProperties() override;\n\n    //Force reporting\n    /** \n     * Methods to query a Force for the value actually applied during simulation\n     * The names of the quantities (column labels) is returned by this first function\n     * getRecordLabels()\n     */\n    OpenSim::Array<std::string> getRecordLabels() const override {\n        OpenSim::Array<std::string> labels("");\n        labels.append(getName()+"_tension");\n        return labels;\n    }\n    /**\n     * Given SimTK::State object extract all the values necessary to report forces, application location\n     * frame, etc. used in conjunction with getRecordLabels and should return same size Array\n     */\n    OpenSim::Array<double> getRecordValues(const SimTK::State& state) const override {\n        OpenSim::Array<double> values(1);\n        values.append(getTension(state));\n        return values;\n    }\n\nprivate:\n    void constructProperties();\n\n//=============================================================================\n};  // END of class PathSpring\n//=============================================================================\n//=============================================================================\n} // end of namespace OpenSim\n\n#endif // OPENSIM_PATH_SPRING_H_\n', 'message': 'Merge pull request #1614 from opensim-org/extendFinalizeFromProperties-PathSprings\n\nadd checks for valid property values for ClutchedPathSpring and PathSpring classes', 'author_name': 'GitHub', 'lang': 'h'}