45#include "brains/Thermo.hpp"
55#include "types/FixedChargeAdapter.hpp"
56#include "types/FluctuatingChargeAdapter.hpp"
57#include "types/MultipoleAdapter.hpp"
58#include "utils/Constants.hpp"
59#include "utils/simError.h"
61#include "math/AlphaHull.hpp"
62#include "math/ConvexHull.hpp"
68 RealType Thermo::getTranslationalKinetic() {
71 if (!snap->hasTranslationalKineticEnergy) {
72 SimInfo::MoleculeIterator miter;
73 vector<StuntDouble*>::iterator iiter;
78 RealType kinetic(0.0);
82 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
83 sd = mol->nextIntegrableObject(iiter)) {
88 mass * (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
93 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
97 kinetic = kinetic * 0.5 / Constants::energyConvert;
99 snap->setTranslationalKineticEnergy(kinetic);
101 return snap->getTranslationalKineticEnergy();
104 RealType Thermo::getRotationalKinetic() {
107 if (!snap->hasRotationalKineticEnergy) {
108 SimInfo::MoleculeIterator miter;
109 vector<StuntDouble*>::iterator iiter;
115 RealType kinetic(0.0);
119 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
120 sd = mol->nextIntegrableObject(iiter)) {
129 kinetic += angMom[j] * angMom[j] / I(j, j) +
130 angMom[k] * angMom[k] / I(k, k);
132 kinetic += angMom[0] * angMom[0] / I(0, 0) +
133 angMom[1] * angMom[1] / I(1, 1) +
134 angMom[2] * angMom[2] / I(2, 2);
141 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
145 kinetic = kinetic * 0.5 / Constants::energyConvert;
147 snap->setRotationalKineticEnergy(kinetic);
149 return snap->getRotationalKineticEnergy();
152 RealType Thermo::getKinetic() {
155 if (!snap->hasKineticEnergy) {
156 RealType ke = getTranslationalKinetic() + getRotationalKinetic() +
157 getElectronicKinetic();
159 snap->setKineticEnergy(ke);
161 return snap->getKineticEnergy();
164 RealType Thermo::getPotential() {
169 return snap->getPotentialEnergy();
172 potVec Thermo::getSelectionPotentials() {
177 return snap->getSelectionPotentials();
180 RealType Thermo::getTotalEnergy() {
183 if (!snap->hasTotalEnergy) {
184 snap->setTotalEnergy(this->getKinetic() + this->getPotential());
187 return snap->getTotalEnergy();
193 RealType Thermo::getTemperature() {
196 if (!snap->hasTemperature) {
198 this->getTranslationalKinetic() + this->getRotationalKinetic();
200 RealType temperature {};
206 temperature = (2.0 * nuclearKE) / (info_->
getNdf() * Constants::kb);
210 snap->setTemperature(temperature);
213 return snap->getTemperature();
216 RealType Thermo::getElectronicKinetic() {
219 if (!snap->hasElectronicKineticEnergy) {
220 SimInfo::MoleculeIterator miter;
221 vector<Atom*>::iterator iiter;
226 RealType kinetic(0.0);
230 for (atom = mol->beginFluctuatingCharge(iiter); atom != NULL;
231 atom = mol->nextFluctuatingCharge(iiter)) {
232 cmass = atom->getChargeMass();
234 kinetic += cmass * cvel * cvel;
239 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
244 snap->setElectronicKineticEnergy(kinetic);
247 return snap->getElectronicKineticEnergy();
250 RealType Thermo::getElectronicTemperature() {
253 if (!snap->hasElectronicTemperature) {
254 RealType eTemp = (2.0 * this->getElectronicKinetic()) /
257 snap->setElectronicTemperature(eTemp);
260 return snap->getElectronicTemperature();
263 RealType Thermo::getNetCharge() {
266 if (!snap->hasNetCharge) {
267 SimInfo::MoleculeIterator miter;
268 vector<Atom*>::iterator aiter;
272 RealType netCharge(0.0);
276 for (atom = mol->beginAtom(aiter); atom != NULL;
277 atom = mol->nextAtom(aiter)) {
281 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
285 if (fqa.isFluctuatingCharge()) { charge += atom->
getFlucQPos(); }
292 MPI_Allreduce(MPI_IN_PLACE, &netCharge, 1, MPI_REALTYPE, MPI_SUM,
296 snap->setNetCharge(netCharge);
299 return snap->getNetCharge();
302 RealType Thermo::getChargeMomentum() {
305 if (!snap->hasChargeMomentum) {
306 SimInfo::MoleculeIterator miter;
307 vector<Atom*>::iterator iiter;
312 RealType momentum(0.0);
316 for (atom = mol->beginFluctuatingCharge(iiter); atom != NULL;
317 atom = mol->nextFluctuatingCharge(iiter)) {
318 cmass = atom->getChargeMass();
321 momentum += cmass * cvel;
326 MPI_Allreduce(MPI_IN_PLACE, &momentum, 1, MPI_REALTYPE, MPI_SUM,
330 snap->setChargeMomentum(momentum);
333 return snap->getChargeMomentum();
336 std::vector<Vector3d> Thermo::getCurrentDensity() {
340 SimInfo::MoleculeIterator miter;
341 std::vector<Atom*>::iterator iiter;
342 std::vector<RigidBody*>::iterator ri;
347 AtomTypeSet::iterator at;
349 std::vector<Vector3d> typeJc(simTypes.size(), V3Zero);
354 for (rb = mol->beginRigidBody(ri); rb != NULL;
355 rb = mol->nextRigidBody(ri)) {
359 for (atom = mol->beginAtom(iiter); atom != NULL;
360 atom = mol->nextAtom(iiter)) {
367 if (fca.isFixedCharge()) q = fca.getCharge();
369 if (fqa.isFluctuatingCharge()) q += atom->
getFlucQPos();
372 at = std::find(simTypes.begin(), simTypes.end(), atype);
373 if (at != simTypes.end()) {
374 typeIndex = std::distance(simTypes.begin(), at);
377 if (typeIndex != -1) { typeJc[typeIndex] += q * v; }
383 MPI_Allreduce(MPI_IN_PLACE, &Jc[0], 3, MPI_REALTYPE, MPI_SUM,
385 for (
unsigned int j = 0; j < simTypes.size(); j++) {
386 MPI_Allreduce(MPI_IN_PLACE, &typeJc[j][0], 3, MPI_REALTYPE, MPI_SUM,
391 RealType vol = snap->getVolume();
393 Jc /= (vol * Constants::currentDensityConvert);
394 for (
unsigned int j = 0; j < simTypes.size(); j++) {
395 typeJc[j] /= (vol * Constants::currentDensityConvert);
398 std::vector<Vector3d> result;
401 result.push_back(Jc);
402 for (
unsigned int j = 0; j < simTypes.size(); j++)
403 result.push_back(typeJc[j]);
408 RealType Thermo::getVolume() {
410 return snap->getVolume();
413 RealType Thermo::getPressure() {
416 if (!snap->hasPressure) {
424 pressure = Constants::pressureConvert *
425 (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0;
427 snap->setPressure(pressure);
430 return snap->getPressure();
433 RealType Thermo::getPressure(
Snapshot* snap) {
434 if (!snap->hasPressure) {
441 pressure = Constants::pressureConvert *
442 (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0;
444 snap->setPressure(pressure);
447 return snap->getPressure();
456 if (!snap->hasPressureTensor) {
462 SimInfo::MoleculeIterator i;
463 vector<StuntDouble*>::iterator j;
468 for (sd = mol->beginIntegrableObject(j); sd != NULL;
469 sd = mol->nextIntegrableObject(j)) {
472 p_tens += mass * outProduct(vcom, vcom);
478 MPI_SUM, MPI_COMM_WORLD);
481 RealType volume = this->getVolume();
482 Mat3x3d virialTensor = snap->getVirialTensor();
485 (p_tens + Constants::energyConvert * virialTensor) / volume;
487 snap->setPressureTensor(pressureTensor);
489 return snap->getPressureTensor();
496 if (!snap->hasPressureTensor) {
502 SimInfo::MoleculeIterator i;
503 vector<StuntDouble*>::iterator j;
508 for (sd = mol->beginIntegrableObject(j); sd != NULL;
509 sd = mol->nextIntegrableObject(j)) {
512 p_tens += mass * outProduct(vcom, vcom);
518 MPI_SUM, MPI_COMM_WORLD);
521 RealType volume = this->getVolume();
522 Mat3x3d virialTensor = snap->getVirialTensor();
525 (p_tens + Constants::energyConvert * virialTensor) / volume;
527 snap->setPressureTensor(pressureTensor);
529 return snap->getPressureTensor();
535 if (!snap->hasSystemDipole) {
536 SimInfo::MoleculeIterator miter;
537 vector<Atom*>::iterator aiter;
550 RealType chargeToC = 1.60217733e-19;
551 RealType angstromToM = 1.0e-10;
552 RealType debyeToCm = 3.33564095198e-30;
556 for (atom = mol->beginAtom(aiter); atom != NULL;
557 atom = mol->nextAtom(aiter)) {
561 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
565 if (fqa.isFluctuatingCharge()) { charge += atom->
getFlucQPos(); }
577 }
else if (charge > 0.0) {
583 if (atom->isDipole()) {
584 dipoleVector += atom->
getDipole() * debyeToCm;
590 MPI_Allreduce(MPI_IN_PLACE, &pChg, 1, MPI_REALTYPE, MPI_SUM,
592 MPI_Allreduce(MPI_IN_PLACE, &nChg, 1, MPI_REALTYPE, MPI_SUM,
595 MPI_Allreduce(MPI_IN_PLACE, &pCount, 1, MPI_INTEGER, MPI_SUM,
597 MPI_Allreduce(MPI_IN_PLACE, &nCount, 1, MPI_INTEGER, MPI_SUM,
601 MPI_SUM, MPI_COMM_WORLD);
603 MPI_SUM, MPI_COMM_WORLD);
606 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
613 RealType chg_value = nChg <= pChg ? nChg : pChg;
616 if (pCount > 0 && nCount > 0) {
622 boxDipole += (pPos - nPos) * chg_value;
623 snap->setSystemDipole(boxDipole);
626 return snap->getSystemDipole();
632 if (!snap->hasSystemQuadrupole) {
633 SimInfo::MoleculeIterator miter;
634 vector<Atom*>::iterator aiter;
642 RealType chargeToC = 1.60217733e-19;
643 RealType angstromToM = 1.0e-10;
644 RealType debyeToCm = 3.33564095198e-30;
648 for (atom = mol->beginAtom(aiter); atom != NULL;
649 atom = mol->nextAtom(aiter)) {
657 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
661 if (fqa.isFluctuatingCharge()) { charge += atom->
getFlucQPos(); }
665 qpole += 0.5 * charge * outProduct(ri, ri);
671 qpole += 0.5 * outProduct(dipole, ri);
672 qpole += 0.5 * outProduct(ri, dipole);
675 if (ma.isQuadrupole()) {
683 MPI_SUM, MPI_COMM_WORLD);
686 snap->setSystemQuadrupole(qpole);
689 return snap->getSystemQuadrupole();
695 SimInfo::MoleculeIterator miter;
696 vector<StuntDouble*>::iterator iiter;
699 RigidBody::AtomIterator ai;
719 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
720 sd = mol->nextIntegrableObject(iiter)) {
724 kinetic = mass * (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
734 kinetic += angMom[j] * angMom[j] / I(j, j) +
735 angMom[k] * angMom[k] / I(k, k);
737 kinetic += angMom[0] * angMom[0] / I(0, 0) +
738 angMom[1] * angMom[1] / I(1, 1) +
739 angMom[2] * angMom[2] / I(2, 2);
747 for (atom = rb->beginAtom(ai); atom != NULL;
748 atom = rb->nextAtom(ai)) {
755 potential *= Constants::energyConvert;
757 eatom = (kinetic + potential) / 2.0;
758 heatFluxJc[0] += eatom * vel[0];
759 heatFluxJc[1] += eatom * vel[1];
760 heatFluxJc[2] += eatom * vel[2];
769 MPI_Allreduce(MPI_IN_PLACE, &heatFluxJc[0], 3, MPI_REALTYPE, MPI_SUM,
776 currSnapshot->getConductiveHeatFlux() * Constants::energyConvert;
779 return (heatFluxJv + heatFluxJc) / this->getVolume();
785 if (!snap->hasCOMvel) {
786 SimInfo::MoleculeIterator i;
790 RealType totalMass(0.0);
794 RealType mass = mol->
getMass();
800 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
803 MPI_SUM, MPI_COMM_WORLD);
807 snap->setCOMvel(comVel);
809 return snap->getCOMvel();
816 SimInfo::MoleculeIterator i;
820 RealType totalMass(0.0);
824 RealType mass = mol->
getMass();
826 com += mass * mol->
getCom();
830 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
833 MPI_SUM, MPI_COMM_WORLD);
839 return snap->getCOM();
849 if (!(snap->hasCOM && snap->hasCOMvel)) {
850 SimInfo::MoleculeIterator i;
853 RealType totalMass(0.0);
860 RealType mass = mol->
getMass();
862 com += mass * mol->
getCom();
867 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
870 MPI_SUM, MPI_COMM_WORLD);
872 MPI_SUM, MPI_COMM_WORLD);
878 snap->setCOMvel(comVel);
880 com = snap->getCOM();
881 comVel = snap->getCOMvel();
898 Molecule::IntegrableObjectIterator j;
901 if (!(snap->hasInertiaTensor && snap->hasCOMw)) {
913 SimInfo::MoleculeIterator i;
924 for (sd = mol->beginIntegrableObject(j); sd != NULL;
925 sd = mol->nextIntegrableObject(j)) {
927 v = sd->
getVel() - comVel;
932 xx += r[0] * r[0] * m;
933 yy += r[1] * r[1] * m;
934 zz += r[2] * r[2] * m;
937 xy += r[0] * r[1] * m;
938 xz += r[0] * r[2] * m;
939 yz += r[1] * r[2] * m;
941 angularMomentum +=
cross(r, v) * m;
945 Itmp += A.transpose() * sd->
getI() * A;
946 angularMomentum += sd->
getJ();
951 inertiaTensor(0, 0) = yy + zz;
952 inertiaTensor(0, 1) = -xy;
953 inertiaTensor(0, 2) = -xz;
954 inertiaTensor(1, 0) = -xy;
955 inertiaTensor(1, 1) = xx + zz;
956 inertiaTensor(1, 2) = -yz;
957 inertiaTensor(2, 0) = -xz;
958 inertiaTensor(2, 1) = -yz;
959 inertiaTensor(2, 2) = xx + yy;
961 inertiaTensor += Itmp;
965 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
967 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
970 snap->setCOMw(angularMomentum);
971 snap->setInertiaTensor(inertiaTensor);
974 angularMomentum = snap->getCOMw();
975 inertiaTensor = snap->getInertiaTensor();
983 if (!(snap->hasBoundingBox)) {
984 SimInfo::MoleculeIterator i;
985 Molecule::RigidBodyIterator ri;
986 Molecule::AtomIterator ai;
996 for (rb = mol->beginRigidBody(ri); rb != NULL;
997 rb = mol->nextRigidBody(ri)) {
1001 for (atom = mol->beginAtom(ai); atom != NULL;
1002 atom = mol->nextAtom(ai)) {
1009 for (
int i = 0; i < 3; i++) {
1010 bMax[i] = max(bMax[i], pos[i]);
1011 bMin[i] = min(bMin[i], pos[i]);
1019 MPI_Allreduce(MPI_IN_PLACE, &bMax[0], 3, MPI_REALTYPE, MPI_MAX,
1022 MPI_Allreduce(MPI_IN_PLACE, &bMin[0], 3, MPI_REALTYPE, MPI_MIN,
1026 for (
int i = 0; i < 3; i++) {
1027 bBox(i, i) = bMax[i] - bMin[i];
1039 if (!snap->hasCOMw) {
1046 SimInfo::MoleculeIterator i;
1057 thisr = mol->
getCom() - com;
1058 thisp = (mol->
getComVel() - comVel) * thisMass;
1060 angularMomentum +=
cross(thisr, thisp);
1065 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1068 snap->setCOMw(angularMomentum);
1071 return snap->getCOMw();
1085 if (!snap->hasGyrationalVolume) {
1089 RealType sysconstants;
1093 geomCnst = 3.0 / 2.0;
1101 4.0 / 3.0 * Constants::PI * pow(sysconstants, geomCnst) * sqrt(det);
1103 snap->setGyrationalVolume(volume);
1105 return snap->getGyrationalVolume();
1111 if (!(snap->hasInertiaTensor && snap->hasGyrationalVolume)) {
1114 RealType sysconstants;
1117 geomCnst = 3.0 / 2.0;
1125 4.0 / 3.0 * Constants::PI * pow(sysconstants, geomCnst) * sqrt(detI);
1126 snap->setGyrationalVolume(volume);
1128 volume = snap->getGyrationalVolume();
1134 RealType Thermo::getTaggedAtomPairDistance() {
1136 Globals* simParams = info_->getSimParams();
1138 if (simParams->haveTaggedAtomPair() &&
1139 simParams->havePrintTaggedPairDistance()) {
1140 if (simParams->getPrintTaggedPairDistance()) {
1141 pair<int, int> tap = simParams->getTaggedAtomPair();
1145 int mol1 = info_->getGlobalMolMembership(tap.first);
1146 int mol2 = info_->getGlobalMolMembership(tap.second);
1152 if (proc1 == worldRank) {
1158 MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
1160 MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
1164 if (proc2 == worldRank) {
1170 MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
1172 MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
1190 RealType Thermo::getHullVolume() {
1193 if (!snap->hasHullVolume) {
1196 Globals* simParams = info_->getSimParams();
1197 const std::string ht = simParams->getHULL_Method();
1199 if (ht ==
"Convex") {
1201 }
else if (ht ==
"AlphaShape") {
1202 surfaceMesh_ =
new AlphaHull(simParams->getAlpha());
1209 std::vector<StuntDouble*> localSites_;
1212 SimInfo::MoleculeIterator i;
1213 Molecule::IntegrableObjectIterator j;
1217 for (sd = mol->beginIntegrableObject(j); sd != NULL;
1218 sd = mol->nextIntegrableObject(j)) {
1219 localSites_.push_back(sd);
1224 surfaceMesh_->computeHull(localSites_);
1225 snap->setHullVolume(surfaceMesh_->getVolume());
1227 delete surfaceMesh_;
1230 return snap->getHullVolume();
Compute alpha complex or alpha shape.
AtomType * getAtomType()
Returns the AtomType of this Atom.
AtomType is what OpenMD looks to for unchanging data about an atom.
RealType getMass()
get total mass of this molecule
Vector3d getComVel()
Returns the velocity of center of mass of this molecule.
Vector3d getCom()
Returns the current center of mass position of this molecule.
Real * getArrayPointer()
Returns the pointer of internal array.
void updateAtoms()
update the positions of atoms belong to this rigidbody
int getNdf()
Returns the number of degrees of freedom.
int getNGlobalIntegrableObjects()
Returns the total number of integrable objects (total number of rigid bodies plus the total number of...
int getMolToProc(int globalIndex)
Finds the processor where a molecule resides.
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
int getNFluctuatingCharges()
Returns the total number of fluctuating charges that are present.
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
SnapshotManager * getSnapshotManager()
Returns the snapshot manager.
StuntDouble * getIOIndexToIntegrableObject(int index)
return an integral objects by its global index.
AtomTypeSet getSimulatedAtomTypes()
Returns the set of atom types present in this simulation.
The Snapshot class is a repository storing dynamic data during a Simulation.
Mat3x3d getBoundingBox()
Returns the Bounding Box.
void setBoundingBox(const Mat3x3d &m)
Sets the Bounding Box.
void wrapVector(Vector3d &v)
Wrapping the vector according to periodic boundary condition.
Snapshot * getCurrentSnapshot()
Returns the pointer of current snapshot.
Real determinant() const
Returns the determinant of this matrix.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
RotMat3x3d getA()
Returns the current rotation matrix of this stuntDouble.
Vector3d getVel()
Returns the current velocity of this stuntDouble.
int linearAxis()
Returns the linear axis of the rigidbody, atom and directional atom will always return -1.
RealType getMass()
Returns the mass of this stuntDouble.
Mat3x3d getQuadrupole()
Returns the current quadrupole tensor of this stuntDouble.
virtual Mat3x3d getI()=0
Returns the inertia tensor of this stuntDouble.
bool isLinear()
Tests the if this stuntDouble is a linear rigidbody.
Vector3d getPos()
Returns the current position of this stuntDouble.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
Vector3d getDipole()
Returns the current dipole vector of this stuntDouble.
RealType getParticlePot()
Returns the current particlePot of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
bool isDirectional()
Tests if this stuntDouble is a directional one.
RealType getFlucQVel()
Returns the current charge velocity of this stuntDouble.
Mat3x3d getPressureTensor()
gives the pressure tensor in amu*fs^-2*Ang^-1
Vector3d getSystemDipole()
accumulate and return the simulation box dipole moment in C*m
void getComAll(Vector3d &com, Vector3d &comVel)
Returns the center of the mass and Center of Mass velocity of the whole system.
void getInertiaTensor(Mat3x3d &inertiaTensor, Vector3d &angularMomentum)
Returns the inertia tensor and the total angular momentum for for the entire system.
RealType getGyrationalVolume()
Returns volume of system as estimated by an ellipsoid defined by the radii of gyration.
Vector3d getCom()
Returns the center of the mass of the whole system.
Mat3x3d getSystemQuadrupole()
accumulate and return the simulation box dipole moment in debye Angstroms
Vector3d getAngularMomentum()
Returns system angular momentum.
Vector3d getComVel()
Returns the velocity of center of mass of the whole system.
Mat3x3d getBoundingBox()
Returns the Axis-aligned bounding box for the current system.
Real & z()
Returns reference of the third element of Vector3.
Real & x()
Returns reference of the first element of Vector3.
Real & y()
Returns reference of the second element of Vector3.
Real length()
Returns the length of this vector.
Real * getArrayPointer()
Returns the pointer of internal array.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.