| 1445 |  | RealType Mc = 0.0; | 
| 1446 |  | Mat3x3d Ic(0.0); | 
| 1447 |  | RealType Kc = 0.0; | 
| 1448 | + |  | 
| 1449 | + | // Constraints can be on only the linear or angular momentum, but | 
| 1450 | + | // not both.  Usually, the user will specify which they want, but | 
| 1451 | + | // in case they don't, the use of periodic boundaries should make | 
| 1452 | + | // the choice for us. | 
| 1453 | + | bool doLinearPart = false; | 
| 1454 | + | bool doAngularPart = false; | 
| 1455 | + |  | 
| 1456 | + | switch (rnemdFluxType_) { | 
| 1457 | + | case rnemdPx: | 
| 1458 | + | case rnemdPy: | 
| 1459 | + | case rnemdPz: | 
| 1460 | + | case rnemdPvector: | 
| 1461 | + | case rnemdKePx: | 
| 1462 | + | case rnemdKePy: | 
| 1463 | + | case rnemdKePvector: | 
| 1464 | + | doLinearPart = true; | 
| 1465 | + | break; | 
| 1466 | + | case rnemdLx: | 
| 1467 | + | case rnemdLy: | 
| 1468 | + | case rnemdLz: | 
| 1469 | + | case rnemdLvector: | 
| 1470 | + | case rnemdKeLx: | 
| 1471 | + | case rnemdKeLy: | 
| 1472 | + | case rnemdKeLz: | 
| 1473 | + | case rnemdKeLvector: | 
| 1474 | + | doAngularPart = true; | 
| 1475 | + | break; | 
| 1476 | + | case rnemdKE: | 
| 1477 | + | case rnemdRotKE: | 
| 1478 | + | case rnemdFullKE: | 
| 1479 | + | default: | 
| 1480 | + | if (usePeriodicBoundaryConditions_) | 
| 1481 | + | doLinearPart = true; | 
| 1482 | + | else | 
| 1483 | + | doAngularPart = true; | 
| 1484 | + | break; | 
| 1485 | + | } | 
| 1486 |  |  | 
| 1487 |  | for (sd = smanA.beginSelected(selei); sd != NULL; | 
| 1488 |  | sd = smanA.nextSelected(selei)) { | 
| 1591 |  | MPI::REALTYPE, MPI::SUM); | 
| 1592 |  | #endif | 
| 1593 |  |  | 
| 1594 | + |  | 
| 1595 | + | Vector3d ac, acrec, bc, bcrec; | 
| 1596 | + | Vector3d ah, ahrec, bh, bhrec; | 
| 1597 | + | RealType cNumerator, cDenominator; | 
| 1598 | + | RealType hNumerator, hDenominator; | 
| 1599 | + |  | 
| 1600 | + |  | 
| 1601 |  | bool successfulExchange = false; | 
| 1602 |  | if ((Mh > 0.0) && (Mc > 0.0)) {//both slabs are not empty | 
| 1603 |  | Vector3d vc = Pc / Mc; | 
| 1604 | < | Vector3d ac = -momentumTarget_ / Mc + vc; | 
| 1605 | < | Vector3d acrec = -momentumTarget_ / Mc; | 
| 1604 | > | ac = -momentumTarget_ / Mc + vc; | 
| 1605 | > | acrec = -momentumTarget_ / Mc; | 
| 1606 |  |  | 
| 1607 |  | // We now need the inverse of the inertia tensor to calculate the | 
| 1608 |  | // angular velocity of the cold slab; | 
| 1609 |  | Mat3x3d Ici = Ic.inverse(); | 
| 1610 |  | Vector3d omegac = Ici * Lc; | 
| 1611 | < | Vector3d bc  = -(Ici * angularMomentumTarget_) + omegac; | 
| 1612 | < | Vector3d bcrec = bc - omegac; | 
| 1611 | > | bc  = -(Ici * angularMomentumTarget_) + omegac; | 
| 1612 | > | bcrec = bc - omegac; | 
| 1613 |  |  | 
| 1614 | < | RealType cNumerator = Kc - kineticTarget_ | 
| 1615 | < | - 0.5 * Mc * ac.lengthSquare() - 0.5 * ( dot(bc, Ic * bc)); | 
| 1614 | > | cNumerator = Kc - kineticTarget_; | 
| 1615 | > | if (doLinearPart) | 
| 1616 | > | cNumerator -= 0.5 * Mc * ac.lengthSquare(); | 
| 1617 | > |  | 
| 1618 | > | if (doAngularPart) | 
| 1619 | > | cNumerator -= 0.5 * ( dot(bc, Ic * bc)); | 
| 1620 | > |  | 
| 1621 |  | if (cNumerator > 0.0) { | 
| 1622 |  |  | 
| 1623 | < | RealType cDenominator = Kc - 0.5 * Mc * vc.lengthSquare() | 
| 1624 | < | - 0.5*(dot(omegac, Ic * omegac)); | 
| 1623 | > | cDenominator = Kc; | 
| 1624 | > |  | 
| 1625 | > | if (doLinearPart) | 
| 1626 | > | cDenominator -= 0.5 * Mc * vc.lengthSquare(); | 
| 1627 | > |  | 
| 1628 | > | if (doAngularPart) | 
| 1629 | > | cDenominator -= 0.5*(dot(omegac, Ic * omegac)); | 
| 1630 |  |  | 
| 1631 |  | if (cDenominator > 0.0) { | 
| 1632 |  | RealType c = sqrt(cNumerator / cDenominator); | 
| 1633 |  | if ((c > 0.9) && (c < 1.1)) {//restrict scaling coefficients | 
| 1634 |  |  | 
| 1635 |  | Vector3d vh = Ph / Mh; | 
| 1636 | < | Vector3d ah = momentumTarget_ / Mh + vh; | 
| 1637 | < | Vector3d ahrec = momentumTarget_ / Mh; | 
| 1636 | > | ah = momentumTarget_ / Mh + vh; | 
| 1637 | > | ahrec = momentumTarget_ / Mh; | 
| 1638 |  |  | 
| 1639 |  | // We now need the inverse of the inertia tensor to | 
| 1640 |  | // calculate the angular velocity of the hot slab; | 
| 1641 |  | Mat3x3d Ihi = Ih.inverse(); | 
| 1642 |  | Vector3d omegah = Ihi * Lh; | 
| 1643 | < | Vector3d bh  = (Ihi * angularMomentumTarget_) + omegah; | 
| 1644 | < | Vector3d bhrec = bh - omegah; | 
| 1643 | > | bh  = (Ihi * angularMomentumTarget_) + omegah; | 
| 1644 | > | bhrec = bh - omegah; | 
| 1645 |  |  | 
| 1646 | < | RealType hNumerator = Kh + kineticTarget_ | 
| 1647 | < | - 0.5 * Mh * ah.lengthSquare() - 0.5 * ( dot(bh, Ih * bh));; | 
| 1646 | > | hNumerator = Kh + kineticTarget_; | 
| 1647 | > | if (doLinearPart) | 
| 1648 | > | hNumerator -= 0.5 * Mh * ah.lengthSquare(); | 
| 1649 | > |  | 
| 1650 | > | if (doAngularPart) | 
| 1651 | > | hNumerator -= 0.5 * ( dot(bh, Ih * bh)); | 
| 1652 | > |  | 
| 1653 |  | if (hNumerator > 0.0) { | 
| 1654 |  |  | 
| 1655 | < | RealType hDenominator = Kh - 0.5 * Mh * vh.lengthSquare() | 
| 1656 | < | - 0.5*(dot(omegah, Ih * omegah)); | 
| 1655 | > | hDenominator = Kh; | 
| 1656 | > | if (doLinearPart) | 
| 1657 | > | hDenominator -= 0.5 * Mh * vh.lengthSquare(); | 
| 1658 | > | if (doAngularPart) | 
| 1659 | > | hDenominator -= 0.5*(dot(omegah, Ih * omegah)); | 
| 1660 |  |  | 
| 1661 |  | if (hDenominator > 0.0) { | 
| 1662 |  | RealType h = sqrt(hNumerator / hDenominator); | 
| 1669 |  | for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) { | 
| 1670 |  | //vel = (*sdi)->getVel(); | 
| 1671 |  | rPos = (*sdi)->getPos() - coordinateOrigin_; | 
| 1672 | < | vel = ((*sdi)->getVel() - vc - cross(omegac, rPos)) * c | 
| 1673 | < | + ac + cross(bc, rPos); | 
| 1672 | > | if (doLinearPart) | 
| 1673 | > | vel = ((*sdi)->getVel() - vc) * c + ac; | 
| 1674 | > | if (doAngularPart) | 
| 1675 | > | vel = ((*sdi)->getVel() - cross(omegac, rPos)) * c + cross(bc, rPos); | 
| 1676 | > |  | 
| 1677 |  | (*sdi)->setVel(vel); | 
| 1678 |  | if (rnemdFluxType_ == rnemdFullKE) { | 
| 1679 |  | if ((*sdi)->isDirectional()) { | 
| 1685 |  | for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) { | 
| 1686 |  | //vel = (*sdi)->getVel(); | 
| 1687 |  | rPos = (*sdi)->getPos() - coordinateOrigin_; | 
| 1688 | < | vel = ((*sdi)->getVel() - vh - cross(omegah, rPos)) * h | 
| 1689 | < | + ah + cross(bh, rPos); | 
| 1688 | > | if (doLinearPart) | 
| 1689 | > | vel = ((*sdi)->getVel() - vh) * h + ah; | 
| 1690 | > | if (doAngularPart) | 
| 1691 | > | vel = ((*sdi)->getVel() - cross(omegah, rPos)) * h + cross(bh, rPos); | 
| 1692 | > |  | 
| 1693 |  | (*sdi)->setVel(vel); | 
| 1694 |  | if (rnemdFluxType_ == rnemdFullKE) { | 
| 1695 |  | if ((*sdi)->isDirectional()) { | 
| 1969 |  | vel.x() = binPx[i] / binMass[i]; | 
| 1970 |  | vel.y() = binPy[i] / binMass[i]; | 
| 1971 |  | vel.z() = binPz[i] / binMass[i]; | 
| 1972 | < | aVel.x() = binOmegax[i]; | 
| 1973 | < | aVel.y() = binOmegay[i]; | 
| 1974 | < | aVel.z() = binOmegaz[i]; | 
| 1972 | > | aVel.x() = binOmegax[i] / binCount[i]; | 
| 1973 | > | aVel.y() = binOmegay[i] / binCount[i]; | 
| 1974 | > | aVel.z() = binOmegaz[i] / binCount[i]; | 
| 1975 |  |  | 
| 1976 |  | if (binCount[i] > 0) { | 
| 1977 |  | // only add values if there are things to add |