64 Tracker(beamline, reference, revBeam, revTrack),
65 itsDataSink_m(nullptr),
66 itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
69 wakeFunction_m(nullptr),
72 dtCurrentTrack_m(0.0),
73 minStepforReBin_m(-1),
74 minBinEmitted_m(
std::numeric_limits<size_t>::
max()),
76 emissionSteps_m(
std::numeric_limits<unsigned int>::
max()),
77 numParticlesInSimulation_m(0),
78 timeIntegrationTimer1_m(
IpplTimings::getTimer(
"TIntegration1")),
79 timeIntegrationTimer2_m(
IpplTimings::getTimer(
"TIntegration2")),
80 fieldEvaluationTimer_m(
IpplTimings::getTimer(
"External field eval")),
81 BinRepartTimer_m(
IpplTimings::getTimer(
"Binaryrepart")),
82 WakeFieldTimer_m(
IpplTimings::getTimer(
"WakeField")),
83 particleMatterStatus_m(false)
92 const std::vector<unsigned long long> &maxSteps,
94 const std::vector<double> &zstop,
95 const std::vector<double> &dt):
96 Tracker(beamline, bunch, reference, revBeam, revTrack),
98 itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
101 wakeFunction_m(nullptr),
104 dtCurrentTrack_m(0.0),
105 minStepforReBin_m(-1),
106 minBinEmitted_m(
std::numeric_limits<size_t>::
max()),
108 emissionSteps_m(
std::numeric_limits<unsigned int>::
max()),
109 numParticlesInSimulation_m(0),
110 timeIntegrationTimer1_m(
IpplTimings::getTimer(
"TIntegration1")),
111 timeIntegrationTimer2_m(
IpplTimings::getTimer(
"TIntegration2")),
112 fieldEvaluationTimer_m(
IpplTimings::getTimer(
"External field eval")),
113 BinRepartTimer_m(
IpplTimings::getTimer(
"Binaryrepart")),
114 WakeFieldTimer_m(
IpplTimings::getTimer(
"WakeField")),
115 particleMatterStatus_m(false)
117 for (
unsigned int i = 0; i < zstop.size(); ++ i) {
145 cavities.insert(cavities.end(), travelingwaves.begin(), travelingwaves.end());
148 if ((*fit).getElement()->getName() == elName) {
155 INFOMSG(
"Restored cavity phase from the h5 file. Name: " << element->
getName() <<
", phase: " << maxPhase <<
" rad" <<
endl);
172 for (; it <
end; ++ it) {
278 *
gmsg <<
"* Executing ParallelTTracker\n"
281 <<
", next step = " << step <<
endl <<
endl;
294 for (; step < trackSteps; ++ step) {
359 msg <<
level2 <<
"Dump phase space of last step" <<
endl;
364 *
gmsg <<
endl <<
"* Done executing ParallelTTracker at "
416 for (
unsigned int i = 0; i < localNum; ++ i) {
440 for (
unsigned int i = 0; i < localNum; ++ i) {
480 if (numParticlesInSimulation_m <= minBinEmitted_m || !itsBunch_m->hasFieldSolver()) {
489 for (
unsigned int i = 0; i < localNum1; ++ i) {
504 binNumber < itsBunch_m->getNumberOfEnergyBins(); ++binNumber) {
519 for (
unsigned int i = 0; i < localNum2; ++ i) {
531 bool locPartOutOfBounds =
false, globPartOutOfBounds =
false;
544 IndexMap::value_t::const_iterator it =
elements.begin();
545 const IndexMap::value_t::const_iterator
end =
elements.end();
547 for (; it !=
end; ++ it) {
554 for (
unsigned int i = 0; i < localNum; ++ i) {
563 if ((*it)->apply(i,
itsBunch_m->
getT() + 0.5 * dt, localE, localB)) {
567 locPartOutOfBounds =
true;
582#ifdef ENABLE_OPAL_FEL
590 if (globPartOutOfBounds) {
606 msg <<
level1 <<
"* Deleted " <<
ne <<
" particles, "
611#ifdef ENABLE_OPAL_FEL
615 IndexMap::value_t::const_iterator it =
elements.begin();
636 bool hasWake =
false;
643 IndexMap::value_t::const_iterator it =
elements.begin();
644 const IndexMap::value_t::const_iterator
end =
elements.end();
646 for (; it !=
end; ++ it) {
647 if ((*it)->hasWake() && !hasWake) {
656 wfInstance = (*it)->getWake();
662 wfInstance = (*it)->getWake();
667 "empty wake function");
671 msg <<
level2 <<
"============== START WAKE CALCULATION =============" <<
endl;
682 for (
unsigned int i = 0; i < localNum; ++ i) {
690 for (
unsigned int i = 0; i < localNum; ++ i) {
701 msg <<
level2 <<
"=============== END WAKE CALCULATION ==============" <<
endl;
708 std::set<IndexMap::value_t::value_type> elementsWithParticleMatterInteraction;
709 std::set<ParticleMatterInteractionHandler*> particleMatterinteractionHandlers;
714 if ((*it)->hasParticleMatterInteraction()) {
715 elementsWithParticleMatterInteraction.insert(*it);
716 particleMatterinteractionHandlers.insert((*it)->getParticleMatterInteraction());
720 currentRange.end =
std::max(currentRange.end, range.
end);
723 elements.insert(touching.begin(), touching.end());
729 if (!elementsWithParticleMatterInteraction.empty()) {
730 std::set<ParticleMatterInteractionHandler*> oldSPHandlers;
731 std::vector<ParticleMatterInteractionHandler*> leftBehindSPHandlers, newSPHandlers;
733 oldSPHandlers.insert(it);
736 leftBehindSPHandlers.resize(
std::max(oldSPHandlers.size(),
737 particleMatterinteractionHandlers.size()));
738 auto last = std::set_difference(oldSPHandlers.begin(), oldSPHandlers.end(),
739 particleMatterinteractionHandlers.begin(), particleMatterinteractionHandlers.end(),
740 leftBehindSPHandlers.begin());
741 leftBehindSPHandlers.resize(last - leftBehindSPHandlers.begin());
743 for (
auto it: leftBehindSPHandlers) {
744 if (!it->stillActive()) {
749 newSPHandlers.resize(
std::max(oldSPHandlers.size(),
750 elementsWithParticleMatterInteraction.size()));
751 last = std::set_difference(particleMatterinteractionHandlers.begin(), particleMatterinteractionHandlers.end(),
752 oldSPHandlers.begin(), oldSPHandlers.end(),
753 newSPHandlers.begin());
754 newSPHandlers.resize(last - newSPHandlers.begin());
756 for (
auto it: newSPHandlers) {
761 msg <<
level2 <<
"============== START PARTICLE MATTER INTERACTION CALCULATION =============" <<
endl;
767 if (!(*it)->stillActive()) {
768 auto next = std::next(it);
782 int degradersWithParticlesCount = 0;
785 if (it->getParticlesInMat() > 0) {
786 onlyDegraderWithParticles = it;
787 ++ degradersWithParticlesCount;
794 unsigned int totalNum = 0;
796 bool allParticlesInMat = (totalNum == 0 &&
797 degradersWithParticlesCount == 1);
799 if (allParticlesInMat) {
801 msg <<
"All particles in degrader" <<
endl;
805 unsigned int rediffusedParticles = 0;
806 unsigned int numEnteredParticles = 0;
814 for (
unsigned int i = 0; i < localNum; ++i) {
818 boundingSphere.first = refToLocalCSTrafo.
transformTo(boundingSphere.first);
823 boundingSphere.first = localToRefCSTrafo.
transformTo(boundingSphere.first);
826 for (
unsigned int i = 0; i < newLocalNum; ++i) {
831 rediffusedParticles += it->getRediffused();
832 numEnteredParticles += it->getNumEntered();
835 if (it->getFlagAllParticlesIn()) {
837 if (timeDifference > 0.0) {
842 for (
unsigned int i = 0; i < numSteps; ++ i) {
853 if (numEnteredParticles > 0 || rediffusedParticles > 0) {
854 totalNum -= (numEnteredParticles + rediffusedParticles);
870 msg <<
level2 <<
"============== END PARTICLE MATTER INTERACTION CALCULATION =============" <<
endl;
880 INFOMSG(
"*****************************************************************" <<
endl);
881 INFOMSG(
"do repartition because of repartFreq_m" <<
endl);
882 INFOMSG(
"*****************************************************************" <<
endl);
887 INFOMSG(
"*****************************************************************" <<
endl);
889 INFOMSG(
"*****************************************************************" <<
endl);
906 msg << myt2.
time() <<
" "
908 <<
" -- no emission yet -- "
917 msg << myt2.
time() <<
" "
919 <<
"only " << std::setw(4) << totalParticles_f <<
" particles emitted; "
925 "there seems to be something wrong with the position of the bunch!");
928 msg << myt2.
time() <<
" "
976 for (
unsigned int i = 0; i < localNum; ++i) {
1006 if (psDump || statDump) {
1019 std::vector<std::pair<std::string, unsigned int> > collimatorLosses;
1021 if (!collimators.empty()) {
1025 unsigned int losses = coll->
getLosses();
1026 collimatorLosses.push_back(std::make_pair(
name, losses));
1028 std::sort(collimatorLosses.begin(), collimatorLosses.end(),
1029 [](
const std::pair<std::string, unsigned int>&
a,
const std::pair<std::string, unsigned int>& b) ->bool {
1030 return a.first < b.first;
1032 std::vector<unsigned int> bareLosses(collimatorLosses.size(),0);
1033 for (
size_t i = 0; i < collimatorLosses.size(); ++ i){
1034 bareLosses[i] = collimatorLosses[i].second;
1037 reduce(&bareLosses[0], &bareLosses[0] + bareLosses.size(), &bareLosses[0],
OpAddAssign());
1039 for (
size_t i = 0; i < collimatorLosses.size(); ++ i){
1040 collimatorLosses[i].second = bareLosses[i];
1046 msg <<
level3 <<
"* Wrote beam statistics." <<
endl;
1059 if (driftToCorrectPosition) {
1062 stashedR.
create(localNum);
1066 for (
size_t i = 0; i < localNum; ++ i) {
1087 if (driftToCorrectPosition) {
1090 stashedR.
destroy(localNum, 0);
1099 msg <<
level2 <<
"* Wrote beam phase space." <<
endl;
1120 IndexMap::value_t::const_iterator it =
elements.begin();
1121 const IndexMap::value_t::const_iterator
end =
elements.end();
1123 for (; it !=
end; ++ it) {
1130 if ((*it)->applyToReferenceParticle(localR,
1135 *
gmsg <<
level1 <<
"The reference particle hit an element" <<
endl;
1152 for (
unsigned int i = 0; i < localNum; ++i) {
1258 for (
auto element: elementSet) {
1294 std::vector<long> localParticles(numNodes, 0);
1300 std::vector<DistributionInfo> send;
1301 std::vector<DistributionInfo> receive;
1304 if (localParticles[i] <= 0)
continue;
1307 if (j == i || localParticles[j] >= 0)
continue;
1309 long numParts =
std::min(localParticles[i], -localParticles[j]);
1310 localParticles[i] -= numParts;
1311 localParticles[j] += numParts;
1320 send.push_back(request);
1322 receive.push_back(request);
1326 if (localParticles[i] == 0)
break;
1330 std::vector<MPI_Request> requests;
1331 const long sizeSingleParticle = 9 *
sizeof(double) +
sizeof(
short) +
sizeof(int) +
sizeof(
PID_t::Return_t);
1335 std::vector<char> send_msgbuf;
1337 if (!send.empty()) {
1340 unsigned int totalSend = 0, startIndex = 0;
1342 totalSend += request.howMany;
1344 send_msgbuf.reserve(totalSend * sizeSingleParticle);
1347 size_t sizePrior = send_msgbuf.size();
1348 for (
long i = 0; i < request.howMany; ++ i, -- idx) {
1349 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
R[idx](0)));
1350 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + 3 *
sizeof(double));
1351 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
P[idx](0)));
1352 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer + 3 *
sizeof(double));
1353 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
Q[idx]));
1354 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(double));
1355 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
M[idx]));
1356 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(double));
1357 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
dt[idx]));
1358 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(double));
1360 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(
ParticleOrigin));
1362 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(int));
1363 buffer =
reinterpret_cast<const char*
>(&(
itsBunch_m->
ID[idx]));
1364 send_msgbuf.insert(send_msgbuf.end(), buffer, buffer +
sizeof(
PID_t::Return_t));
1367 size_t sendSizeThis = send_msgbuf.size() - sizePrior;
1373 requests.push_back(req);
1375 startIndex += sendSizeThis;
1381 for (
unsigned int i = 0; i < receive.size(); ++ i) {
1388 while (j < bufsize) {
1392 const double *buffer =
reinterpret_cast<const double*
>(recvbuf + j);
1399 j += 9 *
sizeof(double);
1408 const int *buffer =
reinterpret_cast<const int*
>(recvbuf + j);
1423 if (!requests.empty()) {
1424 MPI_Waitall(requests.size(), &(requests[0]), MPI_STATUSES_IGNORE);
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Quaternion getQuaternion(Vector_t u, Vector_t ref)
std::list< ClassicField > FieldList
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Tps< T > sqrt(const Tps< T > &x)
Square root.
T euclidean_norm(const Vector< T > &)
Euclidean norm.
void allreduce(const T *input, T *output, int count, Op op)
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
#define P_SPATIAL_TRANSFER_TAG
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
PETE_TBTree< OpNE, Index::PETE_Expr_t, PETE_Scalar< double > > ne(const Index &idx, double x)
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
PETE_TBTree< FnCopysign, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > copysign(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Inform & level2(Inform &inf)
Inform & endl(Inform &inf)
Inform & level1(Inform &inf)
Inform & level3(Inform &inf)
std::string::const_iterator iterator_t
constexpr double e
The value of.
constexpr double c
The velocity of light in m/s.
constexpr double Vpm2MVpm
std::string::iterator iterator
T isinf(T x)
isinf function with adjusted return type
T isnan(T x)
isnan function with adjusted return type
int psDumpFreq
The frequency to dump the phase space, i.e.dump data when steppsDumpFreq==0.
int minBinEmitted
The number of bins that have to be emitted before the bin are squashed into a single bin.
int minStepForRebin
The number of steps into the simulation before the bins are squashed into a single bin.
int repartFreq
The frequency to do particles repartition for better load balance between nodes.
int statDumpFreq
The frequency to dump statistical values, e.e. dump data when stepstatDumpFreq==0.
double getKineticEnergy(Vector_t p, double mass)
std::string getEnergyString(double energyInMeV, unsigned int precision=3)
std::string getTimeString(double time, unsigned int precision=3)
double getGamma(Vector_t p)
std::string getLengthString(double spos, unsigned int precision=3)
ParticleAttrib< Vector_t > Ef
double get_meanKineticEnergy() const
virtual void resetInterpolationCache(bool clearCache=false)
ParticleAttrib< int > Bin
void get_bounds(Vector_t &rmin, Vector_t &rmax) const
virtual void computeSelfFields()=0
size_t getLocalNum() const
ParticleAttrib< double > M
size_t emitParticles(double eZ)
Emit particles in the given bin i.e. copy the particles from the bin structure into the particle cont...
size_t getTotalNum() const
ParticleAttrib< Vector_t > P
void switchToUnitlessPositions(bool use_dt_per_particle=false)
double getEmissionDeltaT()
ParticleAttrib< ParticleOrigin > POrigin
ParticleAttrib< double > Q
int getLastEmittedEnergyBin()
void calcBeamParameters()
Vector_t get_pmean_Distribution() const
size_t getNumberOfEmissionSteps()
CoordinateSystemTrafo toLabTrafo_m
void setGlobalMeanR(Vector_t globalMeanR)
virtual void do_binaryRepart()
ParticleAttrib< int > TriID
void calcGammas()
Compute the gammas of all bins.
ParticleAttrib< double > dt
virtual void setBinCharge(int bin, double q)
Set the charge of one bin to the value of q and all other to zero.
int getNumberOfEnergyBins()
Vector_t get_centroid() const
Vector_t get_pmean() const
void destroy(size_t M, size_t I, bool doNow=false)
ParticleAttrib< Vector_t > Bf
long long getGlobalTrackStep() const
std::pair< Vector_t, double > getLocalBoundingSphere()
void switchOffUnitlessPositions(bool use_dt_per_particle=false)
std::vector< MaxPhasesT >::iterator getLastMaxPhases()
double getGlobalPhaseShift()
units: (sec)
std::vector< MaxPhasesT >::iterator getFirstMaxPhases()
Object * find(const std::string &name)
Find entry.
void setInPrepState(bool state)
void setPriorTrack(const bool &value=true)
true if in follow-up track
void setGlobalPhaseShift(double shift)
units: (sec)
static OpalData * getInstance()
void setOpenMode(OpenMode openMode)
double getPhaseAtMaxEnergy(const Vector_t &R, const Vector_t &P, double t, double dt)
std::set< std::shared_ptr< Component > > value_t
IndexMap::value_t query(IndexMap::key_t::first_type step, IndexMap::key_t::second_type length)
BoundingBox getBoundingBox() const
IndexMap::value_t getTouchingElements(const IndexMap::key_t &range) const
IndexMap::key_t getRange(const IndexMap::value_t::value_type &element, double position) const
void selectDT(bool backTrack=false)
void computeExternalFields(OrbitThreader &oth)
bool hasEndOfLineReached(const BoundingBox &globalBoundingBox)
IpplTimings::TimerRef timeIntegrationTimer2_m
IpplTimings::TimerRef WakeFieldTimer_m
OpalBeamline itsOpalBeamline_m
double zstart_m
where to start
void transformBunch(const CoordinateSystemTrafo &trafo)
void autophaseCavities(const BorisPusher &pusher)
void computeWakefield(IndexMap::value_t &elements)
void computeSpaceChargeFields(unsigned long long step)
virtual void visitBeamline(const Beamline &)
Apply the algorithm to a beam line.
void timeIntegration2(BorisPusher &pusher)
virtual ~ParallelTTracker()
void updateReferenceParticle(const BorisPusher &pusher)
std::set< ParticleMatterInteractionHandler * > activeParticleMatterInteractionHandlers_m
WakeFunction * wakeFunction_m
void doBinaryRepartition()
size_t numParticlesInSimulation_m
void restoreCavityPhases()
virtual void execute()
Apply the algorithm to the top-level beamline.
IpplTimings::TimerRef timeIntegrationTimer1_m
void setOptionalVariables()
void pushParticles(const BorisPusher &pusher)
void dumpStats(long long step, bool psDump, bool statDump)
void changeDT(bool backTrack=false)
void emitParticles(long long step)
void findStartPosition(const BorisPusher &pusher)
void computeParticleMatterInteraction(IndexMap::value_t elements, OrbitThreader &oth)
bool particleMatterStatus_m
unsigned int repartFreq_m
void updateRFElement(std::string elName, double maxPhi)
void timeIntegration1(BorisPusher &pusher)
IpplTimings::TimerRef BinRepartTimer_m
void writePhaseSpace(const long long step, bool psDump, bool statDump)
StepSizeConfig stepSizes_m
IpplTimings::TimerRef fieldEvaluationTimer_m
void evenlyDistributeParticles()
void applyFractionalStep(const BorisPusher &pusher, double tau)
void kickParticles(const BorisPusher &pusher)
void updateReference(const BorisPusher &pusher)
void updateRefToLabCSTrafo()
unsigned int emissionSteps_m
double getMinTimeStep() const
StepSizeConfig & advanceToPos(double spos)
void shiftZStopLeft(double back)
void push_back(double dt, double zstop, unsigned long numSteps)
unsigned long getNumSteps() const
unsigned long long getMaxSteps() const
void sortAscendingZStop()
double getFinalZStop() const
virtual const std::string & getName() const
Get element name.
void getMisalignment(double &x, double &y, double &s) const
virtual void accept(BeamlineVisitor &visitor) const =0
Apply visitor.
CoordinateSystemTrafo getCSTrafoGlobal2Local() const
unsigned int getLosses() const
static void writeStatistics()
virtual bool getAutophaseVeto() const
virtual void setPhasem(double phase)
virtual void setAutophaseVeto(bool veto=true)
void apply(PartBunchBase< double, 3 > *itsBunch, CoordinateSystemTrafo const &refToLocalCSTrafo)
bool getHasBeenSimulated() const
const PartData itsReference
The reference information.
Vector_t rotateFrom(const Vector_t &r) const
Vector_t transformFrom(const Vector_t &r) const
Vector_t transformTo(const Vector_t &r) const
Vector_t rotateTo(const Vector_t &r) const
CoordinateSystemTrafo inverted() const
double getP() const
The constant reference momentum per particle.
Quaternion conjugate() const
const Beamline & itsBeamline_m
PartBunchBase< double, 3 > * itsBunch_m
The bunch of particles to be tracked.
An abstract sequence of beam line components.
bool getRelativeFlag() const
Quaternion getInitialDirection() const
Vector_t getOrigin3D() const
virtual void iterate(BeamlineVisitor &, bool r2l) const
Apply visitor to all elements of the line.
void setFlagAllParticlesIn(bool p)
virtual void initialize(const ElementBase *)
virtual void apply(PartBunchBase< double, 3 > *bunch)=0
bool isOutside(const Vector_t &position) const
FieldList getElementByType(ElementType)
Vector_t rotateToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
CoordinateSystemTrafo getMisalignment(const std::shared_ptr< Component > &comp) const
void merge(OpalBeamline &rhs)
Vector_t transformToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
CoordinateSystemTrafo getCSTrafoLab2Local(const std::shared_ptr< Component > &comp) const
unsigned long getFieldAt(const unsigned int &, const Vector_t &, const long &, const double &, Vector_t &, Vector_t &)
std::set< std::shared_ptr< Component > > getElements(const Vector_t &x)
void swap(OpalBeamline &rhs)
void kick(const Vector_t &R, Vector_t &P, const Vector_t &Ef, const Vector_t &Bf, const double &dt) const
void push(Vector_t &R, const Vector_t &P, const double &dt) const
void dumpSDDS(PartBunchBase< double, 3 > *beam, Vector_t FDext[], const double &azimuth=-1) const
void storeCavityInformation()
Write cavity information from H5 file.
void dumpH5(PartBunchBase< double, 3 > *beam, Vector_t FDext[]) const
The base class for all OPAL exceptions.
std::string time() const
Return time.
virtual double getReal() const
Return value.
virtual void destroy(size_t M, size_t I, bool optDestroy=true)
virtual void create(size_t)
virtual MPI_Request raw_isend(void *, int, int, int)
virtual int raw_probe_receive(char *&, int &, int &)
int next_tag(int t, int s=1000)
static Communicate * Comm
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)
Vektor< double, 3 > Vector_t