Commit ce94de6d authored by Malte Heithoff's avatar Malte Heithoff
Browse files

Add Multithreading test

parent 3a5e0b95
......@@ -36,4 +36,22 @@ public class ThreadingOptimizerTest extends AbstractSymtabTest {
String restPath = "paperMatrixModifier/l2/";
testFilesAreEqual(files, restPath);
}
@Test
public void testMathUnitThreadingAutopilot() throws IOException {
TaggingResolver symtab = createSymTabAndTaggingResolver("src/test/resources");
EMAComponentInstanceSymbol componentSymbol = symtab.<EMAComponentInstanceSymbol>resolve("de.rwth.armin.modeling.autopilot.autopilot", EMAComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentSymbol);
GeneratorCPP generatorCPP = new GeneratorCPP();
generatorCPP.setUseThreadingOptimization(true);
generatorCPP.useOctaveBackend();
generatorCPP.setGenerateCMake(false);
generatorCPP.setGenerationTargetPath("./target/generated-sources-cpp/autopilot/multithreading");
List<File> files = generatorCPP.generateFiles(symtab, componentSymbol);;
String restPath = "autopilot/multithreading/";
testFilesAreEqual(files, restPath);
}
}
#ifndef HELPER_H
#define HELPER_H
#include <iostream>
#include <octave/oct.h>
#include <octave/octave.h>
#include <octave/parse.h>
#include <octave/interpreter.h>
#include <stdarg.h>
#include <initializer_list>
#include "octave/builtin-defun-decls.h"
class Helper
{
public:
static void init()
{
string_vector argv(2);
argv(0) = "embedded";
argv(1) = "-q";
octave_main(2, argv.c_str_vec(), 1);
//octave_debug=1;
//feval ("pkg", ovl ("load", "all"), 0);
}
static octave_value_list convertToOctaveValueList(double a)
{
octave_value_list in;
in(0) = a;
return in;
}
static octave_value_list convertToOctaveValueList(Matrix a)
{
octave_value_list in;
in(0) = a;
return in;
}
static octave_value_list convertToOctaveValueList(RowVector a)
{
octave_value_list in;
in(0) = a;
return in;
}
static octave_value_list convertToOctaveValueList(ColumnVector a)
{
octave_value_list in;
in(0) = a;
return in;
}
static octave_value_list convertToOctaveValueList(double a, double b)
{
octave_value_list in;
in(0) = a;
in(1) = b;
return in;
}
static octave_value_list convertToOctaveValueList(std::initializer_list<double> args)
{
octave_value_list in;
int counter = 0;
for(double element : args) {
in(counter) = octave_value(element);
++counter;
}
return in;
}
static octave_value_list convertToOctaveValueList(Matrix a, double b)
{
octave_value_list in;
in(0) = a;
in(1) = b;
return in;
}
static octave_value_list convertToOctaveValueList(RowVector a, double b)
{
octave_value_list in;
in(0) = a;
in(1) = b;
return in;
}
static octave_value_list convertToOctaveValueList(ColumnVector a, double b)
{
octave_value_list in;
in(0) = a;
in(1) = b;
return in;
}
static octave_value_list callOctaveFunction(octave_value_list in, std::string functionName,int argsOut)
{
/*octave_idx_type n = 2;
octave_value_list in;
for(octave_idx_type i = 0; i < n; i++)
in(i) = octave_value(5 * (i + 2));
octave_value_list out = feval("gcd", in, 1);
if(!error_state && out.length() > 0)
std::cout << "GCD of [" << in(0).int_value() << ", " << in(1).int_value() << "] is " << out(0).int_value()
<< std::endl;
else
std::cout << "invalid\n";
clean_up_and_exit(0);*/
/* if(functionName=="eigs")
return feval(functionName, in, 2);
else if(functionName=="kmeans")
return feval(functionName, in, 2);
*/
return feval(functionName, in, argsOut);
}
static int callOctaveFunctionIntFirstResult(octave_value_list in, std::string functionName, int argsOut)
{
// printf("callOctaveFunctionIntFirstResult pre return functionName: %s\n",functionName.c_str());
return callOctaveFunction(in, functionName,argsOut)(0).int_value();
}
static double callOctaveFunctionDoubleFirstResult(octave_value_list in, std::string functionName, int argsOut)
{
// printf("callOctaveFunctionDoubleFirstResult pre return functionName: %s\n",functionName.c_str());
return callOctaveFunction(in, functionName,argsOut)(0).double_value();
}
static Matrix callOctaveFunctionMatrixFirstResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(0).matrix_value();
}
static ColumnVector callOctaveFunctionColumnVectorFirstResult(octave_value_list in, std::string functionName, int argsOut)
{
printf("pre Call %s\n", functionName.c_str());
try {
in=octave_value_list();
octave_value_list list = callOctaveFunction(in, functionName,argsOut);
printf("post Call %s\n", functionName.c_str());
return list(0).array_value().as_column();
} catch(const std::exception& e) {
printf("%s\n", e.what());
}
return ColumnVector();
}
static RowVector callOctaveFunctionRowVectorFirstResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(0).array_value().as_row();
}
static int callOctaveFunctionIntSecondResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(1).int_value();
}
static double callOctaveFunctionDoubleSecondResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(1).double_value();
}
static Matrix callOctaveFunctionMatrixSecondResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(1).matrix_value();
}
static ColumnVector callOctaveFunctionColumnVectorSecondResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(1).array_value().as_column();
}
static RowVector callOctaveFunctionRowVectorSecondResult(octave_value_list in, std::string functionName, int argsOut)
{
return callOctaveFunction(in, functionName,argsOut)(1).array_value().as_row();
}
static Matrix getMatrixFromOctaveListFirstResult(octave_value_list list){
return list(0).matrix_value();
}
static RowVector getRowVectorFromOctaveListFirstResult(octave_value_list list){
return list(0).array_value().as_row();
}
static ColumnVector getColumnVectorFromOctaveListFirstResult(octave_value_list list){
return list(0).array_value().as_column();
}
static double getDoubleFromOctaveListFirstResult(octave_value_list list){
return list(0).double_value();
}
static int getIntFromOctaveListFirstResult(octave_value_list list){
return list(0).int_value();
}
static Matrix getSqrtMatrixDiag(Matrix A){
int rows = Helper::getDoubleFromOctaveListFirstResult(Fsize(Helper::convertToOctaveValueList(A),0));
for(int i=0;i<rows;++i){
double curVal = A(i,i);
A(i,i) = sqrt(curVal);
}
return A;
}
static Matrix invertDiagMatrix(Matrix A){
int rows = Helper::getDoubleFromOctaveListFirstResult(Fsize(Helper::convertToOctaveValueList(A),0));
for(int i=0;i<rows;++i){
double curVal = A(i,i);
A(i,i) = 1/curVal;
}
return A;
}
};
#endif // HELPER_H
\ No newline at end of file
#ifndef DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT
#define DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include "octave/oct.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_c2cd.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_motionPlanning.h"
#include <thread>
class de_rwth_armin_modeling_autopilot_autopilot{
public:
double timeIncrement;
double currentVelocity;
double x;
double y;
double compass;
double currentEngine;
double currentSteering;
double currentBrakes;
int trajectory_length;
Matrix trajectory_x;
Matrix trajectory_y;
double engine;
double steering;
double brakes;
de_rwth_armin_modeling_autopilot_autopilot_c2cd c2cd;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration behaviorGeneration;
de_rwth_armin_modeling_autopilot_autopilot_motionPlanning motionPlanning;
void init()
{
trajectory_x=Matrix(1,100);
trajectory_y=Matrix(1,100);
c2cd.init();
behaviorGeneration.init();
motionPlanning.init();
}
void execute()
{
motionPlanning.engineAndBrakes.pidParams.currentVelocity = currentVelocity;
motionPlanning.engineAndBrakes.pidError.currentVelocity = currentVelocity;
behaviorGeneration.trimPath.currentPositionX = x;
behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.currentPositionX = x;
behaviorGeneration.calcMotionCmds.driveToFirstPosition.currentPositionX = x;
behaviorGeneration.calcMotionCmds.followTrajectory.currentPositionX = x;
behaviorGeneration.trimPath.currentPositionY = y;
behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.currentPositionY = y;
behaviorGeneration.calcMotionCmds.driveToFirstPosition.currentPositionY = y;
behaviorGeneration.calcMotionCmds.followTrajectory.currentPositionY = y;
c2cd.compass = compass;
behaviorGeneration.trimPath.plannedTrajectoryLength = trajectory_length;
behaviorGeneration.trimPath.plannedTrajectoryX = trajectory_x;
behaviorGeneration.trimPath.plannedTrajectoryY = trajectory_y;
motionPlanning.boundsSteering.eb.lowerBound = -0.785;
motionPlanning.boundsSteering.eb.upperBound = 0.785;
motionPlanning.boundsBrakes.eb.lowerBound = 0;
motionPlanning.boundsBrakes.eb.upperBound = 3;
motionPlanning.boundsEngine.eb.lowerBound = 0;
motionPlanning.boundsEngine.eb.upperBound = 2.5;
std::thread thread1( [ this ] {this->c2cd.execute();});
std::thread thread2( [ this ] {this->behaviorGeneration.trimPath.execute();});
thread1.join();
thread2.join();
motionPlanning.keepDirection.sab.v1x = c2cd.currentDirectionX;
motionPlanning.keepDirection.sab.v1y = c2cd.currentDirectionY;
behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.trimmedTrajectoryLength = behaviorGeneration.trimPath.trimmedTrajectoryLength;
behaviorGeneration.calcMotionCmds.driveToFirstPosition.trimmedTrajectoryLength = behaviorGeneration.trimPath.trimmedTrajectoryLength;
behaviorGeneration.calcMotionCmds.followTrajectory.trimmedTrajectoryLength = behaviorGeneration.trimPath.trimmedTrajectoryLength;
behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.trimmedTrajectoryX = behaviorGeneration.trimPath.trimmedTrajectoryX;
behaviorGeneration.calcMotionCmds.driveToFirstPosition.trimmedTrajectoryX = behaviorGeneration.trimPath.trimmedTrajectoryX;
behaviorGeneration.calcMotionCmds.followTrajectory.trimmedTrajectoryX = behaviorGeneration.trimPath.trimmedTrajectoryX;
behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.trimmedTrajectoryY = behaviorGeneration.trimPath.trimmedTrajectoryY;
behaviorGeneration.calcMotionCmds.driveToFirstPosition.trimmedTrajectoryY = behaviorGeneration.trimPath.trimmedTrajectoryY;
behaviorGeneration.calcMotionCmds.followTrajectory.trimmedTrajectoryY = behaviorGeneration.trimPath.trimmedTrajectoryY;
std::thread thread3( [ this ] {this->behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.execute();});
thread3.join();
behaviorGeneration.calcMotionCmds.driveToFirstPosition.isDriveToFirstPosition = behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.result;
behaviorGeneration.calcMotionCmds.followTrajectory.isDriveToFirstPosition = behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.result;
behaviorGeneration.calcMotionCmds.selector.isDriveToFirstPosition = behaviorGeneration.calcMotionCmds.isDriveToFirstPosition.result;
std::thread thread4( [ this ] {this->behaviorGeneration.calcMotionCmds.driveToFirstPosition.execute();});
std::thread thread5( [ this ] {this->behaviorGeneration.calcMotionCmds.followTrajectory.execute();});
thread4.join();
thread5.join();
behaviorGeneration.calcMotionCmds.selector.desiredDirectionX1 = behaviorGeneration.calcMotionCmds.driveToFirstPosition.desiredDirectionX;
behaviorGeneration.calcMotionCmds.selector.desiredDirectionY1 = behaviorGeneration.calcMotionCmds.driveToFirstPosition.desiredDirectionY;
behaviorGeneration.calcMotionCmds.selector.signedDistanceToTrajectory1 = behaviorGeneration.calcMotionCmds.driveToFirstPosition.signedDistanceToTrajectory;
behaviorGeneration.calcMotionCmds.d2v1.minVelocity = behaviorGeneration.calcMotionCmds.driveToFirstPosition.minVelocity;
behaviorGeneration.calcMotionCmds.d2v1.maxVelocity = behaviorGeneration.calcMotionCmds.driveToFirstPosition.maxVelocity;
behaviorGeneration.calcMotionCmds.d2v1.distance = behaviorGeneration.calcMotionCmds.driveToFirstPosition.distance;
behaviorGeneration.calcMotionCmds.selector.desiredDirectionX2 = behaviorGeneration.calcMotionCmds.followTrajectory.desiredDirectionX;
behaviorGeneration.calcMotionCmds.selector.desiredDirectionY2 = behaviorGeneration.calcMotionCmds.followTrajectory.desiredDirectionY;
behaviorGeneration.calcMotionCmds.selector.signedDistanceToTrajectory2 = behaviorGeneration.calcMotionCmds.followTrajectory.signedDistanceToTrajectory;
behaviorGeneration.calcMotionCmds.d2v2.minVelocity = behaviorGeneration.calcMotionCmds.followTrajectory.minVelocity;
behaviorGeneration.calcMotionCmds.d2v2.maxVelocity = behaviorGeneration.calcMotionCmds.followTrajectory.maxVelocity;
behaviorGeneration.calcMotionCmds.d2v2.distance = behaviorGeneration.calcMotionCmds.followTrajectory.distance;
std::thread thread6( [ this ] {this->behaviorGeneration.calcMotionCmds.d2v1.execute();});
std::thread thread7( [ this ] {this->behaviorGeneration.calcMotionCmds.d2v2.execute();});
thread6.join();
thread7.join();
behaviorGeneration.calcMotionCmds.selector.desiredVelocity1 = behaviorGeneration.calcMotionCmds.d2v1.velocity;
behaviorGeneration.calcMotionCmds.selector.desiredVelocity2 = behaviorGeneration.calcMotionCmds.d2v2.velocity;
std::thread thread8( [ this ] {this->behaviorGeneration.calcMotionCmds.selector.execute();});
thread8.join();
motionPlanning.keepDirection.sab.v2x = behaviorGeneration.calcMotionCmds.selector.desiredDirectionX;
motionPlanning.keepDirection.sab.v2y = behaviorGeneration.calcMotionCmds.selector.desiredDirectionY;
motionPlanning.sac.signedDistanceToTrajectory = behaviorGeneration.calcMotionCmds.selector.signedDistanceToTrajectory;
motionPlanning.engineAndBrakes.pidParams.desiredVelocity = behaviorGeneration.calcMotionCmds.selector.desiredVelocity;
motionPlanning.engineAndBrakes.pidError.desiredVelocity = behaviorGeneration.calcMotionCmds.selector.desiredVelocity;
std::thread thread9( [ this ] {this->motionPlanning.keepDirection.sab.execute();});
std::thread thread10( [ this ] {this->motionPlanning.sac.execute();});
std::thread thread11( [ this ] {this->motionPlanning.engineAndBrakes.pidParams.execute();});
std::thread thread12( [ this ] {this->motionPlanning.engineAndBrakes.pidError.execute();});
thread9.join();
thread10.join();
thread11.join();
thread12.join();
motionPlanning.sum1.t1 = motionPlanning.keepDirection.sab.angle;
motionPlanning.sum1.t2 = motionPlanning.sac.steeringAngleCorrection;
motionPlanning.engineAndBrakes.pid.paramP = motionPlanning.engineAndBrakes.pidParams.paramP;
motionPlanning.engineAndBrakes.pid.paramI = motionPlanning.engineAndBrakes.pidParams.paramI;
motionPlanning.engineAndBrakes.pid.paramD = motionPlanning.engineAndBrakes.pidParams.paramD;
motionPlanning.engineAndBrakes.pid.paramDecayCoefficient = motionPlanning.engineAndBrakes.pidParams.paramDecayCoefficient;
motionPlanning.engineAndBrakes.abs1.input = motionPlanning.engineAndBrakes.pidError.error;
motionPlanning.engineAndBrakes.engineOrBrakes.error = motionPlanning.engineAndBrakes.pidError.error;
std::thread thread13( [ this ] {this->motionPlanning.sum1.execute();});
std::thread thread14( [ this ] {this->motionPlanning.engineAndBrakes.abs1.execute();});
thread13.join();
thread14.join();
motionPlanning.boundsSteering.eb.input = motionPlanning.sum1.result;
motionPlanning.engineAndBrakes.pid.error = motionPlanning.engineAndBrakes.abs1.output;
std::thread thread15( [ this ] {this->motionPlanning.engineAndBrakes.pid.execute();});
std::thread thread16( [ this ] {this->motionPlanning.boundsSteering.eb.execute();});
thread15.join();
thread16.join();
motionPlanning.engineAndBrakes.engineOrBrakes.controlSignal = motionPlanning.engineAndBrakes.pid.control;
steering = motionPlanning.boundsSteering.eb.output;
std::thread thread17( [ this ] {this->motionPlanning.engineAndBrakes.engineOrBrakes.execute();});
thread17.join();
motionPlanning.boundsEngine.eb.input = motionPlanning.engineAndBrakes.engineOrBrakes.engine;
motionPlanning.boundsBrakes.eb.input = motionPlanning.engineAndBrakes.engineOrBrakes.brakes;
std::thread thread18( [ this ] {this->motionPlanning.boundsBrakes.eb.execute();});
std::thread thread19( [ this ] {this->motionPlanning.boundsEngine.eb.execute();});
thread18.join();
thread19.join();
brakes = motionPlanning.boundsBrakes.eb.output;
engine = motionPlanning.boundsEngine.eb.output;
}
};
#endif
#ifndef DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION
#define DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include "octave/oct.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_trimPath.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds.h"
#include <thread>
class de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration{
public:
double currentPositionX;
double currentPositionY;
double currentDirectionX;
double currentDirectionY;
int plannedTrajectoryLength;
Matrix plannedTrajectoryX;
Matrix plannedTrajectoryY;
double desiredDirectionX;
double desiredDirectionY;
double signedDistanceToTrajectory;
double desiredVelocity;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_trimPath trimPath;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds calcMotionCmds;
void init()
{
plannedTrajectoryX=Matrix(1,100);
plannedTrajectoryY=Matrix(1,100);
trimPath.init();
calcMotionCmds.init();
}
void execute()
{
}
};
#endif
#ifndef DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION_CALCMOTIONCMDS
#define DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION_CALCMOTIONCMDS
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include "octave/oct.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_isDriveToFirstPosition.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_driveToFirstPosition.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_d2v1.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_followTrajectory.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_d2v2.h"
#include "de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_selector.h"
#include <thread>
class de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds{
public:
double currentPositionX;
double currentPositionY;
double currentDirectionX;
double currentDirectionY;
int trimmedTrajectoryLength;
Matrix trimmedTrajectoryX;
Matrix trimmedTrajectoryY;
double desiredDirectionX;
double desiredDirectionY;
double signedDistanceToTrajectory;
double desiredVelocity;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_isDriveToFirstPosition isDriveToFirstPosition;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_driveToFirstPosition driveToFirstPosition;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_d2v1 d2v1;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_followTrajectory followTrajectory;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_d2v2 d2v2;
de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_selector selector;
void init()
{
trimmedTrajectoryX=Matrix(1,100);
trimmedTrajectoryY=Matrix(1,100);
isDriveToFirstPosition.init();
driveToFirstPosition.init();
d2v1.init();
followTrajectory.init();
d2v2.init();
selector.init();
}
void execute()
{
}
};
#endif
#ifndef DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION_CALCMOTIONCMDS_D2V1
#define DE_RWTH_ARMIN_MODELING_AUTOPILOT_AUTOPILOT_BEHAVIORGENERATION_CALCMOTIONCMDS_D2V1
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include "octave/oct.h"
#include "Helper.h"
#include "octave/builtin-defun-decls.h"
#include <thread>
class de_rwth_armin_modeling_autopilot_autopilot_behaviorGeneration_calcMotionCmds_d2v1{
public:
double distance;
double minVelocity;
double maxVelocity;
double velocity;
double D1;
double V1;
double D2;
double V2;
double COEF_K;
void init()
{
D1=1;
V1=1;
D2=15;
V2=7;
COEF_K=(Helper::getDoubleFromOctaveListFirstResult(Flog(Helper::convertToOctaveValueList((V1/V2)),1)))/(D2-D1);
}
void execute()
{
double v = 0;
if(((distance < D1))){
v = 0;
}
else if(((distance >= D2))){
v = V2;
}
else {
v = V1*(Helper::getDoubleFromOctaveListFirstResult(Fexp(Helper::convertToOctaveValueList(-COEF_K*(distance-D1)),1)));
}
if(((v < minVelocity))){
v = minVelocity;
}
else if(((v > maxVelocity))){
v = maxVelocity;
}
velocity = v;
}
};
#endif