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