1 /* -------------------------------------------------------------------------- *
2  *                               Simbody(tm)                                  *
3  * -------------------------------------------------------------------------- *
4  * This is part of the SimTK biosimulation toolkit originating from           *
5  * Simbios, the NIH National Center for Physics-Based Simulation of           *
6  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
7  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
8  *                                                                            *
9  * Portions copyright (c) 2009-12 Stanford University and the Authors.        *
10  * Authors: Michael Sherman                                                   *
11  * Contributors:                                                              *
12  *                                                                            *
13  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
14  * not use this file except in compliance with the License. You may obtain a  *
15  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
16  *                                                                            *
17  * Unless required by applicable law or agreed to in writing, software        *
18  * distributed under the License is distributed on an "AS IS" BASIS,          *
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
20  * See the License for the specific language governing permissions and        *
21  * limitations under the License.                                             *
22  * -------------------------------------------------------------------------- */
23 
24 /**@file
25  * Test the Force::Thermostat force element.
26  */
27 
28 #include "SimTKsimbody.h"
29 #include "SimTKcommon/Testing.h"
30 
31 
32 #include <cstdio>
33 #include <exception>
34 #include <iostream>
35 using std::cout; using std::endl;
36 
37 using namespace SimTK;
38 
39 class ThermoReporter : public PeriodicEventReporter {
40 public:
ThermoReporter(const MultibodySystem & sys,const Force::Thermostat & thermo,const Force::LinearBushing & bushing1,const Force::LinearBushing & bushing2,Real dt)41     ThermoReporter(const MultibodySystem& sys,
42                     const Force::Thermostat& thermo,
43                     const Force::LinearBushing& bushing1,
44                     const Force::LinearBushing& bushing2,
45                     Real dt)
46     :   PeriodicEventReporter(dt), system(sys), thermo(thermo),
47         bushing1(bushing1), bushing2(bushing2) {}
48 
handleEvent(const State & state) const49     void handleEvent(const State& state) const override {
50         printf("THERMO t=%g, stage %s, KE+PE=%g Ebath=%g CONSERVED=%g\n",
51                 state.getTime(),
52                 state.getSystemStage().getName().c_str(),
53                 system.calcEnergy(state),
54                 thermo.calcBathEnergy(state),
55                 system.calcEnergy(state)
56                     + thermo.calcBathEnergy(state)
57                     + bushing1.getDissipatedEnergy(state)
58                     + bushing2.getDissipatedEnergy(state));
59         printf("TEMP=%g N=%d Power=%g Work=%g\n",
60             thermo.getCurrentTemperature(state),
61             thermo.getNumThermalDofs(state),
62             thermo.getExternalPower(state),
63             thermo.getExternalWork(state));
64     }
65 private:
66     const MultibodySystem&      system;
67     const Force::Thermostat&    thermo;
68     const Force::LinearBushing& bushing1;
69     const Force::LinearBushing& bushing2;
70 };
71 
testConservationOfEnergy()72 void testConservationOfEnergy() {
73     // Create the system.
74     MultibodySystem         system;
75     SimbodyMatterSubsystem  matter(system);
76     GeneralForceSubsystem   forces(system);
77     Force::UniformGravity   gravity(forces, matter, Vec3(0, -9.8, 0));
78 
79     const Real Mass = 1;
80     const Vec3 HalfShape = Vec3(1,.5,.25)/2;
81     const Transform BodyAttach(Rotation(), Vec3(HalfShape[0],0,0));
82     Body::Rigid brickBody(MassProperties(Mass, Vec3(.1,.2,.3),
83                                 Mass*Inertia(1,1.1,1.2,0.01,0.02,0.03)));
84     //Body::Rigid brickBody(MassProperties(Mass, Vec3(0),
85     //                        Mass*UnitInertia::ellipsoid(HalfShape)));
86     brickBody.addDecoration(Transform(), DecorativeEllipsoid(HalfShape)
87                                             .setOpacity(0.25)
88                                             .setColor(Blue));
89     brickBody.addDecoration(BodyAttach,
90                 DecorativeFrame(0.5).setColor(Red));
91 
92     const int NBod=50;
93     MobilizedBody::Free brick1(matter.Ground(), Transform(),
94                                brickBody,       BodyAttach);
95     MobilizedBody::Free brick2(brick1, Transform(),
96                                brickBody,       BodyAttach);
97     MobilizedBody prev=brick2;
98     MobilizedBody body25;
99     for (int i=0; i<NBod; ++i) {
100         MobilizedBody::Ball next(prev, -1*BodyAttach.p(),
101                                  brickBody, BodyAttach);
102         if (i==25) body25=next;
103         //Force::TwoPointLinearSpring(forces,
104         //    prev, Vec3(0), next, Vec3(0), 1000, 1);
105         prev=next;
106     }
107 
108     Constraint::Ball(matter.Ground(), Vec3(0,1,0)-2*NBod/3*BodyAttach.p(),
109         prev, BodyAttach.p());
110     Constraint::Ball(matter.Ground(), Vec3(0,1,0)-1*NBod/3*BodyAttach.p(),
111         body25, BodyAttach.p());
112 
113 
114     Vec6 k1(1,100,1,100,100,100), c1(0);
115     Force::LinearBushing(forces, matter.Ground(), -2*NBod/3*BodyAttach.p(),
116                  prev, BodyAttach.p(), k1, c1);
117     matter.Ground().addBodyDecoration(-2*NBod/3*BodyAttach.p(),
118         DecorativeFrame().setColor(Green));
119 
120     Force::Thermostat thermo(forces, matter,
121         SimTK_BOLTZMANN_CONSTANT_MD,
122         5000,
123         .1);
124 
125     Vec6 k(1,100,1,100,100,100), c(0);
126     Force::LinearBushing bushing1(forces, matter.Ground(), -1*NBod/3*BodyAttach.p(),
127         brick1, BodyAttach, k, c);
128     Force::LinearBushing bushing2(forces, brick1, Transform(),
129         brick2, BodyAttach, k, c);
130     matter.Ground().addBodyDecoration(-1*NBod/3*BodyAttach.p(),
131         DecorativeFrame().setColor(Green));
132 
133 
134     Visualizer viz(system);
135     Visualizer::Reporter* reporter = new Visualizer::Reporter(viz, 1./30);
136     viz.setBackgroundType(Visualizer::SolidColor);
137     system.addEventReporter(reporter);
138 
139     ThermoReporter* thermoReport = new ThermoReporter
140         (system, thermo, bushing1, bushing2, 1./10);
141     system.addEventReporter(thermoReport);
142 
143     // Initialize the system and state.
144 
145     system.realizeTopology();
146     State state = system.getDefaultState();
147 
148     viz.report(state);
149     printf("Default state -- hit ENTER\n");
150     cout << "t=" << state.getTime()
151          << " q=" << brick1.getQAsVector(state) << brick2.getQAsVector(state)
152          << " u=" << brick1.getUAsVector(state) << brick2.getUAsVector(state)
153          << "\nnChains=" << thermo.getNumChains(state)
154          << " T="        << thermo.getBathTemperature(state)
155          << "\nt_relax=" << thermo.getRelaxationTime(state)
156          << " kB="       << thermo.getBoltzmannsConstant()
157          << endl;
158     getchar();
159 
160     state.setTime(0);
161     system.realize(state, Stage::Acceleration);
162     Vector initU(state.getNU());
163     initU = Test::randVector(state.getNU());
164     state.updU()=initU;
165 
166 
167     RungeKuttaMersonIntegrator integ(system);
168     //integ.setMinimumStepSize(1e-1);
169     integ.setAccuracy(1e-2);
170     TimeStepper ts(system, integ);
171     ts.initialize(state);
172     const State& istate = integ.getState();
173 
174     viz.report(integ.getState());
175     viz.zoomCameraToShowAllGeometry();
176     printf("After initialize -- hit ENTER\n");
177     cout << "t=" << integ.getTime()
178          << "\nE=" << system.calcEnergy(istate)
179          << "\nEbath=" << thermo.calcBathEnergy(istate)
180          << endl;
181     thermoReport->handleEvent(istate);
182     getchar();
183 
184     // Simulate it.
185     ts.stepTo(20.0);
186 
187     viz.report(integ.getState());
188     viz.zoomCameraToShowAllGeometry();
189     printf("After simulation:\n");
190     cout << "t=" << integ.getTime()
191          << "\nE=" << system.calcEnergy(istate)
192          << "\nEbath=" << thermo.calcBathEnergy(istate)
193          << "\nNsteps=" << integ.getNumStepsTaken()
194          << endl;
195     thermoReport->handleEvent(istate);
196 }
197 
main()198 int main() {
199     SimTK_START_TEST("TestThermostat");
200         SimTK_SUBTEST(testConservationOfEnergy);
201     SimTK_END_TEST();
202 }
203