Unverified Commit f55abcaa authored by Evan Pretti's avatar Evan Pretti Committed by GitHub
Browse files

Add constant potential method (#4870)



* Initial implementation of C++ API

* Add kernel interface and information for API generation

* API updates for updating electrode parameters

* Add serialization proxy for ConstantPotentialForce

* Update file headers

* Add CG error tolerance and fix units on getCharges() return value

* Initial implementation of matrix solver

* Fixes and conjugate gradient solver

* Try to fix Linux and Windows builds

* Make sure charge constraint target is on total charge

* Restore handling of exceptions like NonbondedForce since they won't involve electrode atoms

* Ameliorate numerical instability in constrained conjugate gradient

* Fix uninitialized pointers, memory leak, and style

* Set CG tolerance units in Python API

* Test ConstantPotentialForce serialization

* Read/write ExceptionsUsePeriodicBoundaryConditions as bool

* Improve constrained conjugate gradient robustness to roundoff error accumulation

* Recompute matrix if electrode atoms move due to setPositions()

* Tolerance is now in gradient (potential) units again

* Add neutralizing background correction

* Add Python API tests

* Fixes for CG and nonbonded exceptions

* Add initial tests checking against existing NonbondedForce behavior

* Expand test suite and fix some implementation issues

* Add additional tests using larger reference system

* Add Gaussian test

* Finish test against reference computation

* CPU platform implementation

* Fixes for compilation on some platforms

* Fixes for constant potential with AVX/AVX2

* Test linking CPU PME library to constant potential test directly

* Older SWIG versions don't support Python set to C++ set conversion

* Add user guide entry

* Increase speed of reference test

* Conditional building constant potential CPU test is unreliable

* Debugging

* Miscellaneous fixes and improvements for CI

* Cache charges so solver will not run if system and coordinates have not changed

* Preconditioner flag, stability, and automatic detection improvements

* Add GPU platform-specific constant potential kernel classes

* PME and device-host I/O changes to support constant potential

* Initial common constant potential implementation

* Constant potential fixes:

* Fix preconditioner PME position/charge save/restore logic

* Fix reduction synchronization in constant potential solver kernels

* Add double-float accumulation for conjugate gradient solver when
  double unsupported by hardware

* Improve conditioning of a test system, and make sure particles are in or
out of cutoff for consistency and ease of comparing between platforms

* Reorder guess charges for CG when atom reordering changes positions

* Remove PME queue for now

* Trying to debug optimized direct space derivative kernel

* Remove extraneous debugging lines

* Style updates; just make CPU preconditioner double precision

* Debugging updated optimized direct derivatives kernel for all but OpenCL CPU

* OpenCL CPU implementation of direct space derivatives, and cleanup

* Try to make test even shorter to not time out on CI

* Temporary - Debugging

* Debugging

* Debugging

* Debugging

* Debugging

* Remove debugging code and fix reduction synchronization

* Fix other reductions

* Debugging - are tests hanging or just slow on CI?

* Debugging

* Debugging

* Fix macro for case when double precision is available on hardware

* Remove changes for debugging again

* Try to improve matrix solver cache locality by uploading transpose

* Fixes for atom ordering and periodic images

* Can't rely on reorder listener for cell offset updates

* Test reducing number of contexts and timing for CI

* Debugging

* Remove timing code and revert debugging changes

* Matrix solver and plasma term optimizations

* Reduce CG solver kernel calls and downloads

* Don't read back convergence flag from global memory

* Update PME due to refactoring in master branch

* Faster matrix solver (1st step)

* Faster matrix solver for CUDA

* Faster matrix solver compatibility with non-CUDA platforms

* Matrix solver fixes

* Use warp shuffle reductions when possible

* Attempt to work around intermittent compiler crash in Intel CPU OpenCL

* Optimize CG solver kernel 1

* Rework CG solver so some kernels can use more than 1 block

* Don't run out of shared memory

* Asynchronously download convergence flag while clearing buffers

---------
Co-authored-by: default avatarEvan Pretti <pretti@sh03-17n15.int>
parent 0ad62341
......@@ -35,6 +35,7 @@
#include "openmm/CMAPTorsionForce.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/CompoundIntegrator.h"
#include "openmm/ConstantPotentialForce.h"
#include "openmm/CustomAngleForce.h"
#include "openmm/CustomBondForce.h"
#include "openmm/CustomCentroidBondForce.h"
......@@ -80,6 +81,7 @@
#include "openmm/serialization/CMAPTorsionForceProxy.h"
#include "openmm/serialization/CMMotionRemoverProxy.h"
#include "openmm/serialization/CompoundIntegratorProxy.h"
#include "openmm/serialization/ConstantPotentialForceProxy.h"
#include "openmm/serialization/CustomAngleForceProxy.h"
#include "openmm/serialization/CustomBondForceProxy.h"
#include "openmm/serialization/CustomCentroidBondForceProxy.h"
......@@ -140,6 +142,7 @@ extern "C" void registerSerializationProxies() {
SerializationProxy::registerProxy(typeid(CMAPTorsionForce), new CMAPTorsionForceProxy());
SerializationProxy::registerProxy(typeid(CMMotionRemover), new CMMotionRemoverProxy());
SerializationProxy::registerProxy(typeid(CompoundIntegrator), new CompoundIntegratorProxy());
SerializationProxy::registerProxy(typeid(ConstantPotentialForce), new ConstantPotentialForceProxy());
SerializationProxy::registerProxy(typeid(Continuous1DFunction), new Continuous1DFunctionProxy());
SerializationProxy::registerProxy(typeid(Continuous2DFunction), new Continuous2DFunctionProxy());
SerializationProxy::registerProxy(typeid(Continuous3DFunction), new Continuous3DFunctionProxy());
......
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/ConstantPotentialForce.h"
#include "openmm/serialization/XmlSerializer.h"
#include <iostream>
#include <sstream>
using namespace OpenMM;
using namespace std;
void testSerialization() {
// Create a Force.
ConstantPotentialForce force;
force.setForceGroup(3);
force.setName("custom name");
force.setCutoffDistance(2.0);
force.setEwaldErrorTolerance(1e-3);
force.setExceptionsUsePeriodicBoundaryConditions(true);
double alpha = 0.5;
int nx = 3, ny = 5, nz = 7;
force.setPMEParameters(alpha, nx, ny, nz);
force.setConstantPotentialMethod(ConstantPotentialForce::Matrix);
force.setUsePreconditioner(false);
force.setCGErrorTolerance(2e-8);
force.setUseChargeConstraint(true);
force.setChargeConstraintTarget(0.1);
Vec3 externalField(1.0, 2.0, 3.0);
force.setExternalField(externalField);
force.addParticle(1);
force.addParticle(0.0);
force.addParticle(0.0);
force.addParticle(0.0);
force.addParticle(0.0);
force.addParticle(0.0);
force.addParticle(0.5);
force.addParticle(-0.5);
force.addException(0, 6, 2);
force.addException(6, 7, 0.2);
std::set<int> electrode1Particles{1, 2, 4};
std::set<int> electrode2Particles{3, 5};
force.addElectrode(electrode1Particles, 1.0, 0.5, 2.0);
force.addElectrode(electrode2Particles, -0.5, 0.75, 1.5);
// Serialize and then deserialize it.
stringstream buffer;
XmlSerializer::serialize<ConstantPotentialForce>(&force, "Force", buffer);
ConstantPotentialForce* copy = XmlSerializer::deserialize<ConstantPotentialForce>(buffer);
// Compare the two forces to see if they are identical.
ConstantPotentialForce& force2 = *copy;
ASSERT_EQUAL(force.getForceGroup(), force2.getForceGroup());
ASSERT_EQUAL(force.getName(), force2.getName());
ASSERT_EQUAL(force.getCutoffDistance(), force2.getCutoffDistance());
ASSERT_EQUAL(force.getEwaldErrorTolerance(), force2.getEwaldErrorTolerance());
ASSERT_EQUAL(force.getExceptionsUsePeriodicBoundaryConditions(), force2.getExceptionsUsePeriodicBoundaryConditions());
double alpha2;
int nx2, ny2, nz2;
force2.getPMEParameters(alpha2, nx2, ny2, nz2);
ASSERT_EQUAL(alpha, alpha2);
ASSERT_EQUAL(nx, nx2);
ASSERT_EQUAL(ny, ny2);
ASSERT_EQUAL(nz, nz2);
ASSERT_EQUAL(force.getConstantPotentialMethod(), force2.getConstantPotentialMethod());
ASSERT_EQUAL(force.getUsePreconditioner(), force2.getUsePreconditioner());
ASSERT_EQUAL(force.getCGErrorTolerance(), force2.getCGErrorTolerance());
ASSERT_EQUAL(force.getUseChargeConstraint(), force2.getUseChargeConstraint());
ASSERT_EQUAL(force.getChargeConstraintTarget(), force2.getChargeConstraintTarget());
Vec3 externalField2;
force2.getExternalField(externalField2);
ASSERT_EQUAL(externalField, externalField2);
ASSERT_EQUAL(force.getNumParticles(), force2.getNumParticles());
for (int i = 0; i < force.getNumParticles(); i++) {
double charge1, charge2;
force.getParticleParameters(i, charge1);
force2.getParticleParameters(i, charge2);
ASSERT_EQUAL(charge1, charge2);
}
ASSERT_EQUAL(force.getNumExceptions(), force2.getNumExceptions());
for (int i = 0; i < force.getNumExceptions(); i++) {
int a1, a2, b1, b2;
double charge1, charge2;
force.getExceptionParameters(i, a1, b1, charge1);
force2.getExceptionParameters(i, a2, b2, charge2);
ASSERT_EQUAL(a1, a2);
ASSERT_EQUAL(b1, b2);
ASSERT_EQUAL(charge1, charge2);
}
ASSERT_EQUAL(force.getNumElectrodes(), force2.getNumElectrodes());
for (int i = 0; i < force.getNumElectrodes(); i++) {
std::set<int> electrodeParticles1, electrodeParticles2;
double potential1, potential2;
double gaussianWidth1, gaussianWidth2;
double thomasFermiScale1, thomasFermiScale2;
force.getElectrodeParameters(i, electrodeParticles1, potential1, gaussianWidth1, thomasFermiScale1);
force2.getElectrodeParameters(i, electrodeParticles2, potential2, gaussianWidth2, thomasFermiScale2);
ASSERT_EQUAL_CONTAINERS(electrodeParticles1, electrodeParticles2);
ASSERT_EQUAL(potential1, potential2);
ASSERT_EQUAL(gaussianWidth1, gaussianWidth2);
ASSERT_EQUAL(thomasFermiScale1, thomasFermiScale2);
}
}
int main() {
try {
testSerialization();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2025 Stanford University and the Authors. *
* Authors: Peter Eastman, Evan Pretti *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/ConstantPotentialForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <iomanip>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-4;
void testCoulomb(bool periodicExceptions) {
// Ensures that the Coulomb energy and force computation for
// ConstantPotentialForce without electrodes matches NonbondedForce.
System refSystem;
System testSystem;
NonbondedForce* refForce = new NonbondedForce();
ConstantPotentialForce* testForce = new ConstantPotentialForce();
Vec3 a(10, 0, 0);
Vec3 b(1, 9, 0);
Vec3 c(2, 3, 8);
refSystem.setDefaultPeriodicBoxVectors(a, b, c);
testSystem.setDefaultPeriodicBoxVectors(a, b, c);
vector<Vec3> positions;
vector<pair<int, int>> bonds;
for (int i = 0; i < 10; i++) {
refSystem.addParticle(1);
testSystem.addParticle(1);
double testCharge = (i / 2 + 1) * (i % 2 ? -1 : 1);
refForce->addParticle(testCharge, 1, 0);
testForce->addParticle(testCharge);
double f = 0.1 * i;
positions.push_back(f * a + f * f * b + f * f * f * c);
bonds.push_back(pair<int, int>(i, (i + 1) % 10));
}
refForce->createExceptionsFromBonds(bonds, 0.5, 0.0);
testForce->createExceptionsFromBonds(bonds, 0.5);
refForce->setExceptionsUsePeriodicBoundaryConditions(periodicExceptions);
testForce->setExceptionsUsePeriodicBoundaryConditions(periodicExceptions);
refForce->setNonbondedMethod(NonbondedForce::PME);
refForce->setCutoffDistance(3.0);
testForce->setCutoffDistance(3.0);
refSystem.addForce(refForce);
testSystem.addForce(testForce);
ASSERT(testForce->usesPeriodicBoundaryConditions());
ASSERT(testSystem.usesPeriodicBoundaryConditions());
VerletIntegrator refIntegrator(0.001);
VerletIntegrator testIntegrator(0.001);
Context refContext(refSystem, refIntegrator, platform);
Context testContext(testSystem, testIntegrator, platform);
refContext.setPositions(positions);
testContext.setPositions(positions);
State refState = refContext.getState(State::Energy | State::Forces);
State testState = testContext.getState(State::Energy | State::Forces);
const vector<Vec3>& refForces = refState.getForces();
const vector<Vec3>& testForces = testState.getForces();
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), testState.getPotentialEnergy(), TOL);
for (int i = 0; i < refForces.size(); i++) {
ASSERT_EQUAL_VEC(refForces[i], testForces[i], TOL);
}
}
void testCoulombOverlap() {
// Ensures that two particles with an exception can overlap without
// generating NaN energies and forces.
System refSystem;
System testSystem;
NonbondedForce* refForce = new NonbondedForce();
ConstantPotentialForce* testForce = new ConstantPotentialForce();
refSystem.setDefaultPeriodicBoxVectors(Vec3(10, 0, 0), Vec3(0, 10, 0), Vec3(0, 0, 10));
testSystem.setDefaultPeriodicBoxVectors(Vec3(10, 0, 0), Vec3(0, 10, 0), Vec3(0, 0, 10));
for (int i = 0; i < 3; i++) {
refSystem.addParticle(1);
testSystem.addParticle(1);
}
refForce->addParticle(1, 1, 0);
testForce->addParticle(1);
refForce->addParticle(1, 1, 0);
testForce->addParticle(1);
refForce->addParticle(-2, 1, 0);
testForce->addParticle(-2);
refForce->addException(0, 1, 0, 1, 0);
testForce->addException(0, 1, 0);
refForce->setNonbondedMethod(NonbondedForce::PME);
refSystem.addForce(refForce);
testSystem.addForce(testForce);
vector<Vec3> positions{
Vec3(0, 0, 0),
Vec3(0, 0, 0),
Vec3(1, 2, 3)
};
VerletIntegrator refIntegrator(0.001);
VerletIntegrator testIntegrator(0.001);
Context refContext(refSystem, refIntegrator, platform);
Context testContext(testSystem, testIntegrator, platform);
refContext.setPositions(positions);
testContext.setPositions(positions);
State refState = refContext.getState(State::Energy | State::Forces);
State testState = testContext.getState(State::Energy | State::Forces);
const vector<Vec3>& refForces = refState.getForces();
const vector<Vec3>& testForces = testState.getForces();
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), testState.getPotentialEnergy(), TOL);
for (int i = 0; i < refForces.size(); i++) {
ASSERT_EQUAL_VEC(refForces[i], testForces[i], TOL);
}
}
void testCoulombNonNeutral() {
// Ensures that the energy of a non-neutral system at different cutoffs (and
// thus different values of alpha) matches NonbondedForce. Since the latter
// includes a neutralizing plasma correction, this ensures that the same
// correction is working in ConstantPotentialForce.
System refSystem;
System testSystem;
NonbondedForce* refForce = new NonbondedForce();
ConstantPotentialForce* testForce = new ConstantPotentialForce();
Vec3 a, b, c;
a = Vec3(10, 0, 0);
b = Vec3(1, 9, 0);
c = Vec3(2, 3, 8);
refSystem.setDefaultPeriodicBoxVectors(a, b, c);
testSystem.setDefaultPeriodicBoxVectors(a, b, c);
vector<Vec3> positions;
for (int i = 0; i < 10; i++) {
refSystem.addParticle(1);
testSystem.addParticle(1);
double f = 0.1 * i;
refForce->addParticle((i % 2 ? -1 : 1) + f * f, 1, 0);
testForce->addParticle((i % 2 ? -1 : 1) + f * f);
positions.push_back(f * a + f * f * b + f * f * f * c);
}
refForce->setNonbondedMethod(NonbondedForce::PME);
refForce->setCutoffDistance(1.5);
testForce->setCutoffDistance(1.5);
refSystem.addForce(refForce);
testSystem.addForce(testForce);
VerletIntegrator refIntegrator(0.001);
VerletIntegrator testIntegrator(0.001);
Context refContext(refSystem, refIntegrator, platform);
Context testContext(testSystem, testIntegrator, platform);
refContext.setPositions(positions);
testContext.setPositions(positions);
{
State refState = refContext.getState(State::Energy | State::Forces);
State testState = testContext.getState(State::Energy | State::Forces);
const vector<Vec3>& refForces = refState.getForces();
const vector<Vec3>& testForces = testState.getForces();
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), testState.getPotentialEnergy(), TOL);
for (int i = 0; i < refForces.size(); i++) {
ASSERT_EQUAL_VEC(refForces[i], testForces[i], TOL);
}
}
refForce->setCutoffDistance(2.5);
testForce->setCutoffDistance(2.5);
refContext.reinitialize(true);
testContext.reinitialize(true);
{
State refState = refContext.getState(State::Energy | State::Forces);
State testState = testContext.getState(State::Energy | State::Forces);
const vector<Vec3>& refForces = refState.getForces();
const vector<Vec3>& testForces = testState.getForces();
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), testState.getPotentialEnergy(), TOL);
for (int i = 0; i < refForces.size(); i++) {
ASSERT_EQUAL_VEC(refForces[i], testForces[i], TOL);
}
}
}
void testCoulombGaussian() {
// Ensures that Gaussian charge interactions are computed correctly by
// comparing a ConstantPotentialForce-containing system with Gaussian
// charges to a NonbondedForce-containing system with point charges.
System testSystem;
ConstantPotentialForce* testForce = new ConstantPotentialForce();
testSystem.setDefaultPeriodicBoxVectors(Vec3(10, 0, 0), Vec3(0, 10, 0), Vec3(0, 0, 10));
testSystem.addParticle(0);
testSystem.addParticle(0);
testSystem.addParticle(0);
testForce->addParticle(2);
testForce->addParticle(0);
testForce->addParticle(0);
set<int> electrode1{1};
testForce->addElectrode(electrode1, 0, 0.2, 0);
set<int> electrode2{2};
testForce->addElectrode(electrode2, 0, 0.3, 0);
testSystem.addForce(testForce);
vector<Vec3> positions{Vec3(0, 0, 0), Vec3(0.9, 0, 0), Vec3(0.6, 0.4, 0)};
VerletIntegrator testIntegrator(0.001);
Context testContext(testSystem, testIntegrator, platform);
testContext.setPositions(positions);
vector<double> charges;
testForce->getCharges(testContext, charges);
System refSystem;
NonbondedForce* refForce = new NonbondedForce();
refSystem.setDefaultPeriodicBoxVectors(Vec3(10, 0, 0), Vec3(0, 10, 0), Vec3(0, 0, 10));
refSystem.addParticle(0);
refSystem.addParticle(0);
refSystem.addParticle(0);
refForce->addParticle(charges[0], 1, 0);
refForce->addParticle(charges[1], 1, 0);
refForce->addParticle(charges[2], 1, 0);
refForce->setNonbondedMethod(NonbondedForce::PME);
refSystem.addForce(refForce);
VerletIntegrator refIntegrator(0.001);
Context refContext(refSystem, refIntegrator, platform);
refContext.setPositions(positions);
State testState = testContext.getState(State::Energy);
State refState = refContext.getState(State::Energy);
Vec3 x01 = positions[1] - positions[0];
Vec3 x02 = positions[2] - positions[0];
Vec3 x12 = positions[2] - positions[1];
double r01 = sqrt(x01.dot(x01));
double r02 = sqrt(x02.dot(x02));
double r12 = sqrt(x12.dot(x12));
double du_pair = -ONE_4PI_EPS0 * (
charges[0] * charges[1] * erfc(r01 / 0.2) / r01 +
charges[0] * charges[2] * erfc(r02 / 0.3) / r02 +
charges[1] * charges[2] * erfc(r12 / sqrt(0.13)) / r12
);
double du_self = ONE_4PI_EPS0 * (charges[1] * charges[1] / 0.2 + charges[2] * charges[2] / 0.3) / sqrt(2 * M_PI);
ASSERT_EQUAL_TOL(refState.getPotentialEnergy() + du_pair + du_self, testState.getPotentialEnergy(), TOL);
}
void testFiniteFieldNonPeriodic() {
// Ensures that the electric field energy is based on an absolute offset
// from the origin and not affected by periodic wrapping.
System testSystem;
Vec3 a, b, c;
a = Vec3(10, 0, 0);
b = Vec3(1, 9, 0);
c = Vec3(2, 3, 8);
testSystem.setDefaultPeriodicBoxVectors(a, b, c);
testSystem.addParticle(0);
Vec3 field(123, -456, 789);
double charge = -2;
ConstantPotentialForce* testForce = new ConstantPotentialForce();
testForce->setEwaldErrorTolerance(1e-4);
testForce->addParticle(charge);
testSystem.addForce(testForce);
VerletIntegrator baseIntegrator(0.001);
Context baseContext(testSystem, baseIntegrator, platform);
baseContext.setPositions(vector<Vec3>{Vec3(0, 0, 0)});
double pmeBaseEnergy = baseContext.getState(State::Energy).getPotentialEnergy();
testForce->setExternalField(field);
Vec3 position(30, 20, -10);
double referenceEnergy = pmeBaseEnergy - charge * field.dot(position);
Vec3 referenceForce = charge * field;
VerletIntegrator testIntegrator(0.001);
Context testContext(testSystem, testIntegrator, platform);
testContext.setPositions(vector<Vec3>{position});
testIntegrator.step(1);
State testState = testContext.getState(State::Energy | State::Forces);
ASSERT_EQUAL_TOL(referenceEnergy, testState.getPotentialEnergy(), TOL);
ASSERT_EQUAL_VEC(referenceForce, testState.getForces()[0], TOL);
}
void testElectrodesDisjoint() {
// Ensures that a particle cannot belong to more than one electrode.
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
for (int i = 0; i < 3; i++) {
system.addParticle(1);
force->addParticle(0);
}
set<int> electrode1{0, 1};
set<int> electrode2{1, 2};
force->addElectrode(electrode1, 0, 0.2, 0);
force->addElectrode(electrode2, 0, 0.2, 0);
system.addForce(force);
VerletIntegrator integrator(0.001);
bool thrown = false;
try {
Context context(system, integrator, platform);
}
catch (const OpenMMException& exception) {
thrown = true;
}
ASSERT(thrown);
}
void testNoElectrodeExceptions() {
// Ensures that a particle cannot belong to both an electrode and an
// exception.
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
for (int i = 0; i < 3; i++) {
system.addParticle(1);
force->addParticle(0);
}
set<int> electrode{0, 1};
force->addElectrode(electrode, 0, 0.2, 0);
force->addException(1, 2, 0);
system.addForce(force);
VerletIntegrator integrator(0.001);
bool thrown = false;
try {
Context context(system, integrator, platform);
}
catch (const OpenMMException& exception) {
thrown = true;
}
ASSERT(thrown);
}
void testElectrodeMatrixNoMass() {
// Ensures that we can use the matrix method when electrode particles have
// no mass, but that we cannot when an electrode particle has mass.
System system1;
ConstantPotentialForce* force1 = new ConstantPotentialForce();
system1.addParticle(0);
system1.addParticle(0);
system1.addParticle(1);
force1->addParticle(0);
force1->addParticle(0);
force1->addParticle(0);
set<int> electrode1{0, 1};
force1->addElectrode(electrode1, 0, 0.2, 0);
force1->setConstantPotentialMethod(ConstantPotentialForce::Matrix);
system1.addForce(force1);
VerletIntegrator integrator1(0.001);
Context context1(system1, integrator1, platform);
System system2;
ConstantPotentialForce* force2 = new ConstantPotentialForce();
system2.addParticle(0);
system2.addParticle(1);
system2.addParticle(1);
force2->addParticle(0);
force2->addParticle(0);
force2->addParticle(0);
set<int> electrode2{0, 1};
force2->addElectrode(electrode2, 0, 0.2, 0);
force2->setConstantPotentialMethod(ConstantPotentialForce::Matrix);
system2.addForce(force2);
VerletIntegrator integrator2(0.001);
bool thrown = false;
try {
Context context2(system2, integrator2, platform);
}
catch (const OpenMMException& exception) {
thrown = true;
}
ASSERT(thrown);
}
void testSmallSystems(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Ensures that solver convergence is achieved on various small systems with
// zero or one degrees of freedom.
// Using one electrode particle with a total charge constraint, the solution
// is uniquely determined.
System system1;
ConstantPotentialForce* force1 = new ConstantPotentialForce();
system1.addParticle(0);
system1.addParticle(1);
force1->addParticle(0);
force1->addParticle(2);
set<int> electrode1{0};
force1->addElectrode(electrode1, 0, 0.2, 0);
force1->setConstantPotentialMethod(method);
force1->setUsePreconditioner(usePreconditioner);
force1->setUseChargeConstraint(true);
force1->setChargeConstraintTarget(5);
system1.addForce(force1);
VerletIntegrator integrator1(0.001);
Context context1(system1, integrator1, platform);
vector<Vec3> positions1{Vec3(0, 0, 0), Vec3(0.5, 0, 0)};
context1.setPositions(positions1);
vector<double> charges1;
force1->getCharges(context1, charges1);
ASSERT_EQUAL(charges1.size(), 2);
ASSERT_EQUAL_TOL(3, charges1[0], TOL);
ASSERT_EQUAL(2, charges1[1]);
// Using two electrode particles with a total charge constraint, there is
// one degree of freedom. Make a symmetric system so that we know the
// solution.
System system2;
ConstantPotentialForce* force2 = new ConstantPotentialForce();
system2.addParticle(0);
system2.addParticle(0);
system2.addParticle(1);
force2->addParticle(0);
force2->addParticle(0);
force2->addParticle(2);
set<int> electrode2{0, 1};
force2->addElectrode(electrode2, 0, 0.2, 0);
force2->setConstantPotentialMethod(method);
force2->setUsePreconditioner(usePreconditioner);
force2->setUseChargeConstraint(true);
force2->setChargeConstraintTarget(5);
system2.addForce(force2);
VerletIntegrator integrator2(0.001);
Context context2(system2, integrator2, platform);
vector<Vec3> positions2{Vec3(-0.25, 0, 0), Vec3(0.25, 0, 0), Vec3(0, 0, 0)};
context2.setPositions(positions2);
vector<double> charges2;
force2->getCharges(context2, charges2);
ASSERT_EQUAL(charges2.size(), 3);
ASSERT_EQUAL_TOL(1.5, charges2[0], TOL);
ASSERT_EQUAL_TOL(1.5, charges2[1], TOL);
ASSERT_EQUAL(2, charges2[2]);
// Using no electrode particles without a total charge constraint, we should
// simply recover the fixed charges.
System system3;
ConstantPotentialForce* force3 = new ConstantPotentialForce();
system3.addParticle(1);
system3.addParticle(1);
force3->addParticle(2);
force3->addParticle(3);
force3->setConstantPotentialMethod(method);
force3->setUsePreconditioner(usePreconditioner);
force3->setUseChargeConstraint(false);
system3.addForce(force3);
VerletIntegrator integrator3(0.001);
Context context3(system3, integrator3, platform);
vector<Vec3> positions3{Vec3(0, 0, 0), Vec3(0.5, 0, 0)};
context3.setPositions(positions3);
vector<double> charges3;
force3->getCharges(context3, charges3);
ASSERT_EQUAL(charges3.size(), 2);
ASSERT_EQUAL(2, charges3[0]);
ASSERT_EQUAL(3, charges3[1]);
// Using one electrode particle without a total charge constraint, there is
// one degree of freedom. Make a symmetric system so that we know the
// solution.
System system4;
ConstantPotentialForce* force4 = new ConstantPotentialForce();
system4.addParticle(0);
system4.addParticle(1);
system4.addParticle(1);
force4->addParticle(0);
force4->addParticle(1);
force4->addParticle(-1);
set<int> electrode4{0};
force4->addElectrode(electrode4, 0, 0.2, 0);
force4->setConstantPotentialMethod(method);
force4->setUsePreconditioner(usePreconditioner);
force4->setUseChargeConstraint(false);
system4.addForce(force4);
VerletIntegrator integrator4(0.001);
Context context4(system4, integrator4, platform);
vector<Vec3> positions4{Vec3(0, 0, 0), Vec3(-0.75, 0, 0), Vec3(0.75, 0, 0)};
context4.setPositions(positions4);
vector<double> charges4;
force4->getCharges(context4, charges4);
ASSERT_EQUAL(charges4.size(), 3);
ASSERT_EQUAL_TOL(0, charges4[0], TOL);
ASSERT_EQUAL(1, charges4[1]);
ASSERT_EQUAL(-1, charges4[2]);
}
void testNoConstraintWithoutElectrode(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// If there are no electrodes (no charge degrees of freedom in the system),
// the user should not be allowed to specify a total charge constraint.
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
system.addParticle(1);
system.addParticle(1);
force->addParticle(1);
force->addParticle(1);
force->setConstantPotentialMethod(method);
force->setUsePreconditioner(usePreconditioner);
force->setUseChargeConstraint(true);
system.addForce(force);
VerletIntegrator integrator(0.001);
bool thrown = false;
try {
Context context(system, integrator, platform);
}
catch (const OpenMMException& exception) {
thrown = true;
}
ASSERT(thrown);
}
void testConstrainCharge(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Ensures that the total charge constraint works correctly, including when
// the system charge target is set to a non-neutral value and the
// non-electrode particles carry a net charge.
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
system.setDefaultPeriodicBoxVectors(Vec3(10, 0, 0), Vec3(0, 10, 0), Vec3(0, 0, 10));
vector<Vec3> positions;
set<int> electrode;
double electrolyteCharge = 0;
for (int i = 0; i < 10; i++) {
system.addParticle(0);
force->addParticle(0);
positions.push_back(Vec3(i, 0, 0));
electrode.insert(i);
}
for (int i = 0; i < 10; i++) {
system.addParticle(1);
double charge = (i % 2 ? -1 : 1) + 0.01 * i * i;
force->addParticle(charge);
positions.push_back(Vec3(i, 5, 5));
electrolyteCharge += charge;
}
double chargeTarget = -2;
force->addElectrode(electrode, 0, 0.2, 0);
force->setConstantPotentialMethod(method);
force->setUsePreconditioner(usePreconditioner);
force->setUseChargeConstraint(true);
force->setChargeConstraintTarget(chargeTarget);
system.addForce(force);
VerletIntegrator integrator(0.001);
Context context(system, integrator, platform);
context.setPositions(positions);
vector<double> charges;
force->getCharges(context, charges);
ASSERT_EQUAL(20, charges.size());
double electrodeCharge = 0;
for (int i = 0; i < 10; i++) {
electrodeCharge += charges[i];
}
ASSERT_EQUAL_TOL(chargeTarget - electrolyteCharge, electrodeCharge, TOL);
}
void makeTestUpdateSystem(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner, System& system, ConstantPotentialForce*& force, vector<Vec3>& positions) {
// Makes a reference system for tests below checking that the properties of
// a system can be changed after context creation.
system = System();
system.setDefaultPeriodicBoxVectors(Vec3(3, 0, 0), Vec3(0, 3, 0), Vec3(0, 0, 3));
force = new ConstantPotentialForce();
system.addParticle(1);
system.addParticle(1);
system.addParticle(1);
system.addParticle(0);
system.addParticle(0);
force->addParticle(1);
force->addParticle(2);
force->addParticle(-3);
force->addParticle(0);
force->addParticle(0);
force->addException(0, 1, 1.5);
force->addException(1, 2, 0);
force->addElectrode({3}, 1, 0.02, 0.3);
force->addElectrode({4}, 2, 0.04, 0.5);
force->setConstantPotentialMethod(method);
force->setUsePreconditioner(usePreconditioner);
force->setUseChargeConstraint(true);
force->setChargeConstraintTarget(5);
force->setExternalField(Vec3(1, 2, 3));
force->setCutoffDistance(1.1);
system.addForce(force);
positions.clear();
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(0, 0, 1));
positions.push_back(Vec3(0, 1, 1));
positions.push_back(Vec3(1, 1, 1));
positions.push_back(Vec3(2, 2, 2));
}
void testUpdate(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Ensures that parameters can be updated and that the results match those
// computed by a completely different system.
System system1, system2;
ConstantPotentialForce* force1, * force2;
vector<Vec3> positions1, positions2;
VerletIntegrator integrator1(0.001), integrator2(0.001);
vector<double> charges1, charges2;
makeTestUpdateSystem(method, usePreconditioner, system1, force1, positions1);
makeTestUpdateSystem(method, usePreconditioner, system2, force2, positions2);
// Make sure to get charges before updating so that the constant potential
// method initializes: we are testing that it reinitializes with the update.
Context context1(system1, integrator1, platform);
context1.setPositions(positions1);
force1->getCharges(context1, charges1);
force1->setParticleParameters(1, 3);
force1->setParticleParameters(2, -5);
force1->setExceptionParameters(0, 0, 1, 1.75);
force1->setElectrodeParameters(0, {3}, 3, 0.06, 0.7);
force1->setChargeConstraintTarget(-7);
force1->setExternalField(Vec3(-6, -4, -2));
force1->updateParametersInContext(context1);
force1->getCharges(context1, charges1);
// Reinitialize the reference system completely to force an update.
force2->setParticleParameters(1, 3);
force2->setParticleParameters(2, -5);
force2->setExceptionParameters(0, 0, 1, 1.75);
force2->setElectrodeParameters(0, {3}, 3, 0.06, 0.7);
force2->setChargeConstraintTarget(-7);
force2->setExternalField(Vec3(-6, -4, -2));
Context context2(system2, integrator2, platform);
context2.setPositions(positions2);
force2->getCharges(context2, charges2);
{
// Test charges.
for (int i = 0; i < charges2.size(); i++) {
ASSERT_EQUAL_TOL(charges2[i], charges1[i], TOL);
}
// Get states and test energies and forces.
State state1 = context1.getState(State::Energy | State::Forces);
State state2 = context2.getState(State::Energy | State::Forces);
const vector<Vec3>& forces1 = state1.getForces();
const vector<Vec3>& forces2 = state2.getForces();
ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), TOL);
for (int i = 0; i < forces2.size(); i++) {
ASSERT_EQUAL_VEC(forces2[i], forces1[i], TOL);
}
}
// Now test updating the box. Get PME parameters to apply to the second
// context so that energies and forces can be compared.
double alpha;
int nx, ny, nz;
force1->getPMEParametersInContext(context1, alpha, nx, ny, nz);
context1.setPeriodicBoxVectors(Vec3(3.25, 0, 0), Vec3(0, 3.5, 0), Vec3(0, 0, 3.75));
force1->getCharges(context1, charges1);
force2->setPMEParameters(alpha, nx, ny, nz);
system2.setDefaultPeriodicBoxVectors(Vec3(3.25, 0, 0), Vec3(0, 3.5, 0), Vec3(0, 0, 3.75));
context2.reinitialize(false);
context2.setPositions(positions2);
force2->getCharges(context2, charges2);
{
// Test charges.
for (int i = 0; i < charges2.size(); i++) {
ASSERT_EQUAL_TOL(charges2[i], charges1[i], TOL);
}
// Get states and test energies and forces.
State state1 = context1.getState(State::Energy | State::Forces);
State state2 = context2.getState(State::Energy | State::Forces);
const vector<Vec3>& forces1 = state1.getForces();
const vector<Vec3>& forces2 = state2.getForces();
ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), TOL);
for (int i = 0; i < forces2.size(); i++) {
ASSERT_EQUAL_VEC(forces2[i], forces1[i], TOL);
}
}
// Now test updating positions. This checks that, e.g., a precomputed
// matrix is invalidated and recomputed when electrode particle positions
// are adjusted.
positions1[0] += Vec3(0.1, 0.2, 0.3);
positions1[4] += Vec3(0.4, 0.5, 0.6);
context1.setPositions(positions1);
force1->getCharges(context1, charges1);
context2.reinitialize(false);
context2.setPositions(positions1);
force2->getCharges(context2, charges2);
{
// Test charges.
for (int i = 0; i < charges2.size(); i++) {
ASSERT_EQUAL_TOL(charges2[i], charges1[i], TOL);
}
// Get states and test energies and forces.
State state1 = context1.getState(State::Energy | State::Forces);
State state2 = context2.getState(State::Energy | State::Forces);
const vector<Vec3>& forces1 = state1.getForces();
const vector<Vec3>& forces2 = state2.getForces();
ASSERT_EQUAL_TOL(state2.getPotentialEnergy(), state1.getPotentialEnergy(), TOL);
for (int i = 0; i < forces2.size(); i++) {
ASSERT_EQUAL_VEC(forces2[i], forces1[i], TOL);
}
}
}
void testParallelPlateCapacitorDoubleCell() {
// Uses the zero field double-cell geometry to test an ideal parallel plate
// capacitor with vacuum between the plates.
double capacitance = EPSILON0 * 2.0 * 3.0 / 7.0;
double potential = 100.0;
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
system.setDefaultPeriodicBoxVectors(Vec3(2, 0, 0), Vec3(0, 3, 0), Vec3(0, 0, 16));
vector<Vec3> positions;
set<int> electrode1, electrode2;
for (int iz = 0; iz < 4; iz++) {
for (int iy = 0; iy < 12; iy++) {
for (int ix = 0; ix < 8; ix++) {
electrode1.insert(force->getNumParticles());
system.addParticle(0);
force->addParticle(0);
positions.push_back(Vec3(0.25 * ix, 0.25 * iy, 0.25 * iz));
electrode2.insert(force->getNumParticles());
system.addParticle(0);
force->addParticle(0);
positions.push_back(Vec3(0.25 * ix, 0.25 * iy, 0.25 * iz + 8.0));
}
}
}
force->addElectrode(electrode1, 0, 0.2, 0);
force->addElectrode(electrode2, potential, 0.2, 0);
force->setUseChargeConstraint(true);
system.addForce(force);
VerletIntegrator integrator(0.001);
Context context(system, integrator, platform);
context.setPositions(positions);
vector<double> charges;
double q1, q2;
force->getCharges(context, charges);
q1 = 0;
for (int ii : electrode1) {
q1 += charges[ii];
}
q2 = 0;
for (int ii : electrode2) {
q2 += charges[ii];
}
// Charge on each electrode is doubled since we are using a double-cell.
// Use a looser tolerance since the analytical formula is for uniform
// plates with defined edges, not cubic arrays of Gaussian charges.
ASSERT_EQUAL_TOL(-2.0 * potential * capacitance, q1, 1e-3);
ASSERT_EQUAL_TOL(2.0 * potential * capacitance, q2, 1e-3);
// Update potential to a new value and recompute.
potential = -200.0;
force->setElectrodeParameters(1, electrode2, potential, 0.2, 0);
force->updateParametersInContext(context);
force->getCharges(context, charges);
q1 = 0;
for (int ii : electrode1) {
q1 += charges[ii];
}
q2 = 0;
for (int ii : electrode2) {
q2 += charges[ii];
}
ASSERT_EQUAL_TOL(-2.0 * potential * capacitance, q1, 1e-3);
ASSERT_EQUAL_TOL(2.0 * potential * capacitance, q2, 1e-3);
}
void testParallelPlateCapacitorFiniteField() {
// Uses the finite field geometry (still applying a potential to one
// electrode) to test an ideal parallel plate capacitor.
double capacitance = EPSILON0 * 2.0 * 3.0 / 11.0;
double potential = 100.0;
System system;
ConstantPotentialForce* force = new ConstantPotentialForce();
system.setDefaultPeriodicBoxVectors(Vec3(2, 0, 0), Vec3(0, 3, 0), Vec3(0, 0, 16));
vector<Vec3> positions;
set<int> electrode1, electrode2;
for (int iz = 0; iz < 4; iz++) {
for (int iy = 0; iy < 12; iy++) {
for (int ix = 0; ix < 8; ix++) {
electrode1.insert(force->getNumParticles());
system.addParticle(0);
force->addParticle(0);
positions.push_back(Vec3(0.25 * ix, 0.25 * iy, 0.25 * iz));
electrode2.insert(force->getNumParticles());
system.addParticle(0);
force->addParticle(0);
positions.push_back(Vec3(0.25 * ix, 0.25 * iy, 0.25 * iz + 12.0));
}
}
}
force->addElectrode(electrode1, 0, 0.2, 0);
force->addElectrode(electrode2, potential, 0.2, 0);
force->setUseChargeConstraint(true);
force->setExternalField(Vec3(0, 0, -potential / 16));
system.addForce(force);
VerletIntegrator integrator(0.001);
Context context(system, integrator, platform);
context.setPositions(positions);
vector<double> charges;
force->getCharges(context, charges);
double q1 = 0;
for (int ii : electrode1) {
q1 += charges[ii];
}
double q2 = 0;
for (int ii : electrode2) {
q2 += charges[ii];
}
// Use a looser tolerance since the analytical formula is for uniform
// plates with defined edges, not cubic arrays of Gaussian charges.
ASSERT_EQUAL_TOL(-potential * capacitance, q1, 1e-3);
ASSERT_EQUAL_TOL(potential * capacitance, q2, 1e-3);
// Update potential to a new value and recompute.
potential = -200.0;
force->setElectrodeParameters(1, electrode2, potential, 0.2, 0);
force->setExternalField(Vec3(0, 0, -potential / 16));
force->updateParametersInContext(context);
force->getCharges(context, charges);
q1 = 0;
for (int ii : electrode1) {
q1 += charges[ii];
}
q2 = 0;
for (int ii : electrode2) {
q2 += charges[ii];
}
ASSERT_EQUAL_TOL(-potential * capacitance, q1, 1e-3);
ASSERT_EQUAL_TOL(potential * capacitance, q2, 1e-3);
}
void makeTestReferenceSystem(bool freezeAll, System& system, ConstantPotentialForce*& constantPotentialForce, vector<Vec3>& positions) {
// Generates a test system with SPC/E water in contact with a model
// electrode.
system = System();
system.setDefaultPeriodicBoxVectors(Vec3(3, 0, 0), Vec3(0, 2, 0), Vec3(0, 0, 2));
HarmonicBondForce* bondForce = new HarmonicBondForce();
NonbondedForce* nonbondedForce = new NonbondedForce();
constantPotentialForce = new ConstantPotentialForce();
for (int i = 0; i < 300; i++) {
system.addParticle((i >= 100 && i < 200) || freezeAll ? 0 : 195.08);
nonbondedForce->addParticle(0, 0.25, 1);
constantPotentialForce->addParticle(0);
}
// static const int bondCount = ...;
// static const int bondIndices[...][2] = {...};
#include "conp_bond_indices.dat"
for (int i = 0; i < bondCount; i++) {
bondForce->addBond(bondIndices[i][0], bondIndices[i][1], 0.28284271247461906, 10000);
}
for (int i = 0; i < 222; i++) {
int i1 = system.addParticle(15.99943);
int i2 = system.addParticle(1.007947);
int i3 = system.addParticle(1.007947);
system.addConstraint(i1, i2, 0.1);
system.addConstraint(i1, i3, 0.1);
system.addConstraint(i2, i3, 0.1632980861841278);
nonbondedForce->addParticle(0, 0.3165719505039882, 0.6497752);
nonbondedForce->addParticle(0, 1, 0);
nonbondedForce->addParticle(0, 1, 0);
nonbondedForce->addException(i1, i2, 0, 1, 0);
nonbondedForce->addException(i1, i3, 0, 1, 0);
nonbondedForce->addException(i2, i3, 0, 1, 0);
constantPotentialForce->addParticle(-0.8476);
constantPotentialForce->addParticle(0.4238);
constantPotentialForce->addParticle(0.4238);
constantPotentialForce->addException(i1, i2, 0);
constantPotentialForce->addException(i1, i3, 0);
constantPotentialForce->addException(i2, i3, 0);
}
bondForce->setUsesPeriodicBoundaryConditions(true);
system.addForce(bondForce);
nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.addForce(nonbondedForce);
positions.clear();
positions.resize(system.getNumParticles());
// positions[...] = Vec3(..., ..., ...);
#include "conp_positions.dat"
set<int> electrodeLeft;
set<int> electrodeRight;
for (int i = 0; i < 300; i++) {
if (positions[i][0] < 1.5) {
electrodeLeft.insert(i);
} else {
electrodeRight.insert(i);
}
}
// Initialize the electrodes (parameters will be set later).
constantPotentialForce->addElectrode(electrodeLeft, 0, 0, 0);
constantPotentialForce->addElectrode(electrodeRight, 0, 0, 0);
system.addForce(constantPotentialForce);
}
void testReferenceCharges(bool testThomasFermi, ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Make sure that charges solved for match values computed by an external
// reference implementation.
System testSystem;
ConstantPotentialForce* testForce;
vector<Vec3> positions;
makeTestReferenceSystem(method == ConstantPotentialForce::Matrix, testSystem, testForce, positions);
testForce->setEwaldErrorTolerance(5e-5);
testForce->setConstantPotentialMethod(method);
testForce->setUsePreconditioner(usePreconditioner);
testForce->setUseChargeConstraint(true);
testForce->setChargeConstraintTarget(0);
testForce->setCutoffDistance(1);
if (!testThomasFermi) {
// The reference implementation (MetalWalls) doesn't support
// simultaneous specification of these options.
testForce->setExternalField(Vec3(100, 50, 25));
}
set<int> electrodeParticles;
double potential, gaussianWidth, thomasFermiScale;
testForce->getElectrodeParameters(0, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
testForce->setElectrodeParameters(0, electrodeParticles, 100, 0.05, testThomasFermi ? 0.50625 : 0.0);
testForce->getElectrodeParameters(1, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
testForce->setElectrodeParameters(1, electrodeParticles, 200, 0.1, testThomasFermi ? 0.225 : 0.0);
VerletIntegrator integrator(0.001);
Context testContext(testSystem, integrator, platform);
testContext.setPositions(positions);
// Charges of electrode atoms should match reference values.
vector<double> refCharges(300);
if (testThomasFermi) {
// refCharges[...] = ...;
#include "conp_ref_charges_tf.dat"
} else {
// refCharges[...] = ...;
#include "conp_ref_charges.dat"
}
vector<double> testCharges;
testForce->getCharges(testContext, testCharges);
for (int i = 0; i < 300; i++) {
ASSERT_EQUAL_TOL(refCharges[i], testCharges[i], TOL);
}
}
void testChargeUpdate(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Make sure that charges get updated correctly before and after dynamics.
System testSystem;
ConstantPotentialForce* testForce;
vector<Vec3> positions;
makeTestReferenceSystem(method == ConstantPotentialForce::Matrix, testSystem, testForce, positions);
testForce->setConstantPotentialMethod(method);
testForce->setUsePreconditioner(usePreconditioner);
testForce->setUseChargeConstraint(true);
testForce->setChargeConstraintTarget(1);
testForce->setExternalField(Vec3(10, 0, 0));
set<int> electrodeParticles;
double potential, gaussianWidth, thomasFermiScale;
testForce->getElectrodeParameters(0, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
testForce->setElectrodeParameters(0, electrodeParticles, 1, 0.05, 1);
testForce->getElectrodeParameters(1, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
testForce->setElectrodeParameters(1, electrodeParticles, 2, 0.06, 1.2);
VerletIntegrator integrator(0.001);
Context testContext(testSystem, integrator, platform);
testContext.setPositions(positions);
testContext.setVelocitiesToTemperature(300);
// Charges of non-electrode atoms should exactly match charges set.
vector<double> charges0;
testForce->getCharges(testContext, charges0);
for (int i = 300; i < charges0.size(); i++) {
double refCharge;
testForce->getParticleParameters(i, refCharge);
ASSERT_EQUAL(refCharge, charges0[i]);
}
integrator.step(1);
// Charges of electrode atoms should be changed, and charges of
// non-electrode atoms should exactly match charges set.
vector<double> charges1;
testForce->getCharges(testContext, charges1);
for (int i = 0; i < 300; i++) {
ASSERT(charges1[i] != charges0[i]);
}
for (int i = 300; i < charges1.size(); i++) {
double refCharge;
testForce->getParticleParameters(i, refCharge);
ASSERT_EQUAL(refCharge, charges1[i]);
}
}
void testEnergyConservation(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner, int stepCount) {
// Do a short dynamics run and ensure that energy is conserved.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(2, 0, 0), Vec3(0, 2, 0), Vec3(0, 0, 3));
// WCA potential to keep particles from getting too close to each other.
CustomNonbondedForce* nonbondedForce = new CustomNonbondedForce("1/r^12-2/r^6+1");
nonbondedForce->setNonbondedMethod(CustomNonbondedForce::CutoffPeriodic);
nonbondedForce->setCutoffDistance(1);
ConstantPotentialForce* constantPotentialForce = new ConstantPotentialForce();
constantPotentialForce->setCutoffDistance(1);
constantPotentialForce->setUseChargeConstraint(true);
constantPotentialForce->setChargeConstraintTarget(1);
constantPotentialForce->setExternalField(Vec3(1, 2, 4));
constantPotentialForce->setConstantPotentialMethod(method);
constantPotentialForce->setUsePreconditioner(usePreconditioner);
constantPotentialForce->setEwaldErrorTolerance(1e-4);
for (int i = 0; i < 8; i++) {
system.addParticle(method == ConstantPotentialForce::Matrix ? 0 : 1);
constantPotentialForce->addParticle(0);
}
for (int i = 0; i < 4; i++) {
system.addParticle(1);
}
for (int i = 0; i < 12; i++) {
nonbondedForce->addParticle();
}
constantPotentialForce->addParticle(1);
constantPotentialForce->addParticle(-1);
constantPotentialForce->addParticle(-1);
constantPotentialForce->addParticle(1);
constantPotentialForce->addElectrode({0, 1, 2, 3}, -8, 0.05, 1);
constantPotentialForce->addElectrode({4, 5, 6, 7}, 8, 0.1, 1.5);
system.addForce(nonbondedForce);
system.addForce(constantPotentialForce);
vector<Vec3> positions{
Vec3(0.0, 0.0, 0.0),
Vec3(0.0, 1.0, 0.0),
Vec3(1.0, 0.0, 0.0),
Vec3(1.0, 1.0, 0.0),
Vec3(0.0, 0.0, 2.0),
Vec3(0.0, 1.0, 2.0),
Vec3(1.0, 0.0, 2.0),
Vec3(1.0, 1.0, 2.0),
Vec3(0.5, 0.5, 1.0),
Vec3(0.5, 1.5, 1.0),
Vec3(1.5, 0.5, 1.0),
Vec3(1.5, 1.5, 1.0)
};
VerletIntegrator integrator(0.002);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(1 / BOLTZ);
State state1 = context.getState(State::Energy);
double energy1 = state1.getPotentialEnergy() + state1.getKineticEnergy();
integrator.step(stepCount);
State state2 = context.getState(State::Energy);
double energy2 = state2.getPotentialEnergy() + state2.getKineticEnergy();
ASSERT_USUALLY_EQUAL_TOL(energy1, energy2, 5e-4);
}
void compareToReferencePlatform(System& system, ConstantPotentialForce* force, const vector<Vec3>& positions) {
// Compares results from the current platform to results computed by the
// reference platform.
VerletIntegrator refIntegrator(0.001);
VerletIntegrator testIntegrator(0.001);
ReferencePlatform refPlatform;
Context refContext(system, refIntegrator, refPlatform);
Context testContext(system, testIntegrator, platform);
refContext.setPositions(positions);
testContext.setPositions(positions);
State refState = refContext.getState(State::Energy | State::Forces);
State testState = testContext.getState(State::Energy | State::Forces);
const vector<Vec3>& refForces = refState.getForces();
const vector<Vec3>& testForces = testState.getForces();
vector<double> refCharges, testCharges;
force->getCharges(refContext, refCharges);
force->getCharges(testContext, testCharges);
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), testState.getPotentialEnergy(), TOL);
for (int i = 0; i < system.getNumParticles(); i++) {
ASSERT_EQUAL_VEC(refForces[i], testForces[i], 3e-3);
}
for (int i = 0; i < system.getNumParticles(); i++) {
ASSERT_EQUAL_TOL(refCharges[i], testCharges[i], TOL);
}
}
void testCompareToReferencePlatform(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
// Compares results between the current and reference platforms for a few
// test systems. This is only called in the runPlatformTests() for
// platforms other than the reference platform.
System system;
ConstantPotentialForce* force;
vector<Vec3> positions;
makeTestUpdateSystem(method, usePreconditioner, system, force, positions);
force->setEwaldErrorTolerance(5e-5);
compareToReferencePlatform(system, force, positions);
makeTestReferenceSystem(method == ConstantPotentialForce::Matrix, system, force, positions);
force->setConstantPotentialMethod(method);
force->setUsePreconditioner(usePreconditioner);
force->setUseChargeConstraint(true);
force->setChargeConstraintTarget(1);
force->setExternalField(Vec3(10, 0, 0));
force->setEwaldErrorTolerance(5e-5);
set<int> electrodeParticles;
double potential, gaussianWidth, thomasFermiScale;
force->getElectrodeParameters(0, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
force->setElectrodeParameters(0, electrodeParticles, 1, 0.05, 1);
force->getElectrodeParameters(1, electrodeParticles, potential, gaussianWidth, thomasFermiScale);
force->setElectrodeParameters(1, electrodeParticles, 2, 0.06, 1.2);
compareToReferencePlatform(system, force, positions);
}
void platformInitialize();
void runPlatformTests(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner);
void runMethodDependentTests(ConstantPotentialForce::ConstantPotentialMethod method, bool usePreconditioner) {
testSmallSystems(method, usePreconditioner);
testNoConstraintWithoutElectrode(method, usePreconditioner);
testConstrainCharge(method, usePreconditioner);
testUpdate(method, usePreconditioner);
testReferenceCharges(false, method, usePreconditioner); // External field
testReferenceCharges(true, method, usePreconditioner); // Thomas-Fermi
testChargeUpdate(method, usePreconditioner);
runPlatformTests(method, usePreconditioner);
}
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
platformInitialize();
testCoulomb(false); // Non-periodic exceptions
testCoulomb(true); // Periodic exceptions
testCoulombOverlap();
testCoulombNonNeutral();
testCoulombGaussian();
testFiniteFieldNonPeriodic();
testElectrodesDisjoint();
testNoElectrodeExceptions();
testElectrodeMatrixNoMass();
testParallelPlateCapacitorDoubleCell();
testParallelPlateCapacitorFiniteField();
runMethodDependentTests(ConstantPotentialForce::Matrix, false); // Matrix inversion (usePreconditioner ignored)
runMethodDependentTests(ConstantPotentialForce::CG, false); // Conjugate gradient (not preconditioned)
runMethodDependentTests(ConstantPotentialForce::CG, true); // Conjugate gradient (preconditioned)
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
......@@ -115,6 +115,9 @@ void testLogic() {
ASSERT_EQUAL(4.0, temp.upperVec()[3]);
ASSERT_VEC8_EQUAL_INT(i1&mask, 0, 2, 3, 0, 0, 6, 7, 0);
ASSERT_VEC8_EQUAL_INT(i1|mask, 1, allBits, allBits, 4, 5, allBits, allBits, 8);
ivec8 i2(1, 2, 4, 3, 7, 6, 5, 8);
ASSERT_VEC8_EQUAL_INT(i1 == i2, -1, -1, 0, 0, 0, -1, 0, -1);
ASSERT_VEC8_EQUAL_INT(i1 != i2, 0, 0, -1, -1, -1, 0, -1, 0);
}
int main(int argc, char* argv[]) {
......
static const int bondCount = 1600;
static const int bondIndices[1600][2] = {
{0, 1},
{0, 2},
{0, 3},
{0, 17},
{0, 18},
{0, 81},
{0, 83},
{0, 97},
{1, 2},
{1, 3},
{1, 4},
{1, 7},
{1, 20},
{1, 22},
{1, 24},
{2, 3},
{2, 4},
{2, 7},
{2, 81},
{2, 83},
{2, 87},
{2, 100},
{2, 101},
{2, 104},
{2, 181},
{3, 17},
{3, 18},
{3, 20},
{3, 22},
{3, 38},
{3, 100},
{3, 101},
{3, 117},
{3, 120},
{4, 5},
{4, 6},
{4, 7},
{4, 81},
{4, 85},
{4, 87},
{5, 6},
{5, 7},
{5, 8},
{5, 11},
{5, 24},
{5, 26},
{5, 28},
{6, 7},
{6, 8},
{6, 11},
{6, 85},
{6, 87},
{6, 91},
{6, 104},
{6, 105},
{6, 108},
{6, 185},
{7, 22},
{7, 24},
{7, 26},
{7, 101},
{7, 104},
{7, 105},
{7, 124},
{8, 9},
{8, 10},
{8, 11},
{8, 85},
{8, 89},
{8, 91},
{9, 10},
{9, 11},
{9, 12},
{9, 15},
{9, 28},
{9, 30},
{9, 32},
{10, 11},
{10, 12},
{10, 15},
{10, 89},
{10, 91},
{10, 95},
{10, 108},
{10, 109},
{10, 112},
{10, 189},
{11, 26},
{11, 28},
{11, 30},
{11, 105},
{11, 108},
{11, 109},
{11, 128},
{12, 13},
{12, 14},
{12, 15},
{12, 89},
{12, 93},
{12, 95},
{13, 14},
{13, 15},
{13, 16},
{13, 19},
{13, 32},
{13, 34},
{13, 36},
{14, 15},
{14, 16},
{14, 19},
{14, 93},
{14, 95},
{14, 99},
{14, 112},
{14, 113},
{14, 116},
{14, 193},
{15, 30},
{15, 32},
{15, 34},
{15, 109},
{15, 112},
{15, 113},
{15, 132},
{16, 17},
{16, 18},
{16, 19},
{16, 93},
{16, 97},
{16, 99},
{17, 18},
{17, 19},
{17, 20},
{17, 36},
{17, 38},
{18, 19},
{18, 83},
{18, 97},
{18, 99},
{18, 100},
{18, 116},
{18, 117},
{18, 197},
{19, 34},
{19, 36},
{19, 38},
{19, 113},
{19, 116},
{19, 117},
{19, 136},
{20, 21},
{20, 22},
{20, 23},
{20, 37},
{20, 38},
{21, 22},
{21, 23},
{21, 24},
{21, 27},
{21, 40},
{21, 42},
{21, 44},
{22, 23},
{22, 24},
{22, 27},
{22, 101},
{22, 120},
{22, 121},
{22, 124},
{23, 37},
{23, 38},
{23, 40},
{23, 42},
{23, 58},
{23, 120},
{23, 121},
{23, 137},
{23, 140},
{24, 25},
{24, 26},
{24, 27},
{25, 26},
{25, 27},
{25, 28},
{25, 31},
{25, 44},
{25, 46},
{25, 48},
{26, 27},
{26, 28},
{26, 31},
{26, 105},
{26, 124},
{26, 125},
{26, 128},
{27, 42},
{27, 44},
{27, 46},
{27, 121},
{27, 124},
{27, 125},
{27, 144},
{28, 29},
{28, 30},
{28, 31},
{29, 30},
{29, 31},
{29, 32},
{29, 35},
{29, 48},
{29, 50},
{29, 52},
{30, 31},
{30, 32},
{30, 35},
{30, 109},
{30, 128},
{30, 129},
{30, 132},
{31, 46},
{31, 48},
{31, 50},
{31, 125},
{31, 128},
{31, 129},
{31, 148},
{32, 33},
{32, 34},
{32, 35},
{33, 34},
{33, 35},
{33, 36},
{33, 39},
{33, 52},
{33, 54},
{33, 56},
{34, 35},
{34, 36},
{34, 39},
{34, 113},
{34, 132},
{34, 133},
{34, 136},
{35, 50},
{35, 52},
{35, 54},
{35, 129},
{35, 132},
{35, 133},
{35, 152},
{36, 37},
{36, 38},
{36, 39},
{37, 38},
{37, 39},
{37, 40},
{37, 56},
{37, 58},
{38, 39},
{38, 117},
{38, 120},
{38, 136},
{38, 137},
{39, 54},
{39, 56},
{39, 58},
{39, 133},
{39, 136},
{39, 137},
{39, 156},
{40, 41},
{40, 42},
{40, 43},
{40, 57},
{40, 58},
{41, 42},
{41, 43},
{41, 44},
{41, 47},
{41, 60},
{41, 62},
{41, 64},
{42, 43},
{42, 44},
{42, 47},
{42, 121},
{42, 140},
{42, 141},
{42, 144},
{43, 57},
{43, 58},
{43, 60},
{43, 62},
{43, 78},
{43, 140},
{43, 141},
{43, 157},
{43, 160},
{44, 45},
{44, 46},
{44, 47},
{45, 46},
{45, 47},
{45, 48},
{45, 51},
{45, 64},
{45, 66},
{45, 68},
{46, 47},
{46, 48},
{46, 51},
{46, 125},
{46, 144},
{46, 145},
{46, 148},
{47, 62},
{47, 64},
{47, 66},
{47, 141},
{47, 144},
{47, 145},
{47, 164},
{48, 49},
{48, 50},
{48, 51},
{49, 50},
{49, 51},
{49, 52},
{49, 55},
{49, 68},
{49, 70},
{49, 72},
{50, 51},
{50, 52},
{50, 55},
{50, 129},
{50, 148},
{50, 149},
{50, 152},
{51, 66},
{51, 68},
{51, 70},
{51, 145},
{51, 148},
{51, 149},
{51, 168},
{52, 53},
{52, 54},
{52, 55},
{53, 54},
{53, 55},
{53, 56},
{53, 59},
{53, 72},
{53, 74},
{53, 76},
{54, 55},
{54, 56},
{54, 59},
{54, 133},
{54, 152},
{54, 153},
{54, 156},
{55, 70},
{55, 72},
{55, 74},
{55, 149},
{55, 152},
{55, 153},
{55, 172},
{56, 57},
{56, 58},
{56, 59},
{57, 58},
{57, 59},
{57, 60},
{57, 76},
{57, 78},
{58, 59},
{58, 137},
{58, 140},
{58, 156},
{58, 157},
{59, 74},
{59, 76},
{59, 78},
{59, 153},
{59, 156},
{59, 157},
{59, 176},
{60, 61},
{60, 62},
{60, 63},
{60, 77},
{60, 78},
{61, 62},
{61, 63},
{61, 64},
{61, 67},
{61, 80},
{61, 82},
{61, 84},
{62, 63},
{62, 64},
{62, 67},
{62, 141},
{62, 160},
{62, 161},
{62, 164},
{63, 77},
{63, 78},
{63, 80},
{63, 82},
{63, 98},
{63, 160},
{63, 161},
{63, 177},
{63, 180},
{64, 65},
{64, 66},
{64, 67},
{65, 66},
{65, 67},
{65, 68},
{65, 71},
{65, 84},
{65, 86},
{65, 88},
{66, 67},
{66, 68},
{66, 71},
{66, 145},
{66, 164},
{66, 165},
{66, 168},
{67, 82},
{67, 84},
{67, 86},
{67, 161},
{67, 164},
{67, 165},
{67, 184},
{68, 69},
{68, 70},
{68, 71},
{69, 70},
{69, 71},
{69, 72},
{69, 75},
{69, 88},
{69, 90},
{69, 92},
{70, 71},
{70, 72},
{70, 75},
{70, 149},
{70, 168},
{70, 169},
{70, 172},
{71, 86},
{71, 88},
{71, 90},
{71, 165},
{71, 168},
{71, 169},
{71, 188},
{72, 73},
{72, 74},
{72, 75},
{73, 74},
{73, 75},
{73, 76},
{73, 79},
{73, 92},
{73, 94},
{73, 96},
{74, 75},
{74, 76},
{74, 79},
{74, 153},
{74, 172},
{74, 173},
{74, 176},
{75, 90},
{75, 92},
{75, 94},
{75, 169},
{75, 172},
{75, 173},
{75, 192},
{76, 77},
{76, 78},
{76, 79},
{77, 78},
{77, 79},
{77, 80},
{77, 96},
{77, 98},
{78, 79},
{78, 157},
{78, 160},
{78, 176},
{78, 177},
{79, 94},
{79, 96},
{79, 98},
{79, 173},
{79, 176},
{79, 177},
{79, 196},
{80, 81},
{80, 82},
{80, 83},
{80, 97},
{80, 98},
{81, 82},
{81, 83},
{81, 84},
{81, 87},
{82, 83},
{82, 84},
{82, 87},
{82, 161},
{82, 180},
{82, 181},
{82, 184},
{83, 97},
{83, 98},
{83, 100},
{83, 180},
{83, 181},
{83, 197},
{84, 85},
{84, 86},
{84, 87},
{85, 86},
{85, 87},
{85, 88},
{85, 91},
{86, 87},
{86, 88},
{86, 91},
{86, 165},
{86, 184},
{86, 185},
{86, 188},
{87, 104},
{87, 181},
{87, 184},
{87, 185},
{88, 89},
{88, 90},
{88, 91},
{89, 90},
{89, 91},
{89, 92},
{89, 95},
{90, 91},
{90, 92},
{90, 95},
{90, 169},
{90, 188},
{90, 189},
{90, 192},
{91, 108},
{91, 185},
{91, 188},
{91, 189},
{92, 93},
{92, 94},
{92, 95},
{93, 94},
{93, 95},
{93, 96},
{93, 99},
{94, 95},
{94, 96},
{94, 99},
{94, 173},
{94, 192},
{94, 193},
{94, 196},
{95, 112},
{95, 189},
{95, 192},
{95, 193},
{96, 97},
{96, 98},
{96, 99},
{97, 98},
{97, 99},
{98, 99},
{98, 177},
{98, 180},
{98, 196},
{98, 197},
{99, 116},
{99, 193},
{99, 196},
{99, 197},
{100, 101},
{100, 102},
{100, 103},
{100, 117},
{100, 118},
{100, 181},
{100, 183},
{100, 197},
{101, 102},
{101, 103},
{101, 104},
{101, 107},
{101, 120},
{101, 122},
{101, 124},
{102, 103},
{102, 104},
{102, 107},
{102, 181},
{102, 183},
{102, 187},
{102, 200},
{102, 201},
{102, 204},
{102, 281},
{103, 117},
{103, 118},
{103, 120},
{103, 122},
{103, 138},
{103, 200},
{103, 201},
{103, 217},
{103, 220},
{104, 105},
{104, 106},
{104, 107},
{104, 181},
{104, 185},
{104, 187},
{105, 106},
{105, 107},
{105, 108},
{105, 111},
{105, 124},
{105, 126},
{105, 128},
{106, 107},
{106, 108},
{106, 111},
{106, 185},
{106, 187},
{106, 191},
{106, 204},
{106, 205},
{106, 208},
{106, 285},
{107, 122},
{107, 124},
{107, 126},
{107, 201},
{107, 204},
{107, 205},
{107, 224},
{108, 109},
{108, 110},
{108, 111},
{108, 185},
{108, 189},
{108, 191},
{109, 110},
{109, 111},
{109, 112},
{109, 115},
{109, 128},
{109, 130},
{109, 132},
{110, 111},
{110, 112},
{110, 115},
{110, 189},
{110, 191},
{110, 195},
{110, 208},
{110, 209},
{110, 212},
{110, 289},
{111, 126},
{111, 128},
{111, 130},
{111, 205},
{111, 208},
{111, 209},
{111, 228},
{112, 113},
{112, 114},
{112, 115},
{112, 189},
{112, 193},
{112, 195},
{113, 114},
{113, 115},
{113, 116},
{113, 119},
{113, 132},
{113, 134},
{113, 136},
{114, 115},
{114, 116},
{114, 119},
{114, 193},
{114, 195},
{114, 199},
{114, 212},
{114, 213},
{114, 216},
{114, 293},
{115, 130},
{115, 132},
{115, 134},
{115, 209},
{115, 212},
{115, 213},
{115, 232},
{116, 117},
{116, 118},
{116, 119},
{116, 193},
{116, 197},
{116, 199},
{117, 118},
{117, 119},
{117, 120},
{117, 136},
{117, 138},
{118, 119},
{118, 183},
{118, 197},
{118, 199},
{118, 200},
{118, 216},
{118, 217},
{118, 297},
{119, 134},
{119, 136},
{119, 138},
{119, 213},
{119, 216},
{119, 217},
{119, 236},
{120, 121},
{120, 122},
{120, 123},
{120, 137},
{120, 138},
{121, 122},
{121, 123},
{121, 124},
{121, 127},
{121, 140},
{121, 142},
{121, 144},
{122, 123},
{122, 124},
{122, 127},
{122, 201},
{122, 220},
{122, 221},
{122, 224},
{123, 137},
{123, 138},
{123, 140},
{123, 142},
{123, 158},
{123, 220},
{123, 221},
{123, 237},
{123, 240},
{124, 125},
{124, 126},
{124, 127},
{125, 126},
{125, 127},
{125, 128},
{125, 131},
{125, 144},
{125, 146},
{125, 148},
{126, 127},
{126, 128},
{126, 131},
{126, 205},
{126, 224},
{126, 225},
{126, 228},
{127, 142},
{127, 144},
{127, 146},
{127, 221},
{127, 224},
{127, 225},
{127, 244},
{128, 129},
{128, 130},
{128, 131},
{129, 130},
{129, 131},
{129, 132},
{129, 135},
{129, 148},
{129, 150},
{129, 152},
{130, 131},
{130, 132},
{130, 135},
{130, 209},
{130, 228},
{130, 229},
{130, 232},
{131, 146},
{131, 148},
{131, 150},
{131, 225},
{131, 228},
{131, 229},
{131, 248},
{132, 133},
{132, 134},
{132, 135},
{133, 134},
{133, 135},
{133, 136},
{133, 139},
{133, 152},
{133, 154},
{133, 156},
{134, 135},
{134, 136},
{134, 139},
{134, 213},
{134, 232},
{134, 233},
{134, 236},
{135, 150},
{135, 152},
{135, 154},
{135, 229},
{135, 232},
{135, 233},
{135, 252},
{136, 137},
{136, 138},
{136, 139},
{137, 138},
{137, 139},
{137, 140},
{137, 156},
{137, 158},
{138, 139},
{138, 217},
{138, 220},
{138, 236},
{138, 237},
{139, 154},
{139, 156},
{139, 158},
{139, 233},
{139, 236},
{139, 237},
{139, 256},
{140, 141},
{140, 142},
{140, 143},
{140, 157},
{140, 158},
{141, 142},
{141, 143},
{141, 144},
{141, 147},
{141, 160},
{141, 162},
{141, 164},
{142, 143},
{142, 144},
{142, 147},
{142, 221},
{142, 240},
{142, 241},
{142, 244},
{143, 157},
{143, 158},
{143, 160},
{143, 162},
{143, 178},
{143, 240},
{143, 241},
{143, 257},
{143, 260},
{144, 145},
{144, 146},
{144, 147},
{145, 146},
{145, 147},
{145, 148},
{145, 151},
{145, 164},
{145, 166},
{145, 168},
{146, 147},
{146, 148},
{146, 151},
{146, 225},
{146, 244},
{146, 245},
{146, 248},
{147, 162},
{147, 164},
{147, 166},
{147, 241},
{147, 244},
{147, 245},
{147, 264},
{148, 149},
{148, 150},
{148, 151},
{149, 150},
{149, 151},
{149, 152},
{149, 155},
{149, 168},
{149, 170},
{149, 172},
{150, 151},
{150, 152},
{150, 155},
{150, 229},
{150, 248},
{150, 249},
{150, 252},
{151, 166},
{151, 168},
{151, 170},
{151, 245},
{151, 248},
{151, 249},
{151, 268},
{152, 153},
{152, 154},
{152, 155},
{153, 154},
{153, 155},
{153, 156},
{153, 159},
{153, 172},
{153, 174},
{153, 176},
{154, 155},
{154, 156},
{154, 159},
{154, 233},
{154, 252},
{154, 253},
{154, 256},
{155, 170},
{155, 172},
{155, 174},
{155, 249},
{155, 252},
{155, 253},
{155, 272},
{156, 157},
{156, 158},
{156, 159},
{157, 158},
{157, 159},
{157, 160},
{157, 176},
{157, 178},
{158, 159},
{158, 237},
{158, 240},
{158, 256},
{158, 257},
{159, 174},
{159, 176},
{159, 178},
{159, 253},
{159, 256},
{159, 257},
{159, 276},
{160, 161},
{160, 162},
{160, 163},
{160, 177},
{160, 178},
{161, 162},
{161, 163},
{161, 164},
{161, 167},
{161, 180},
{161, 182},
{161, 184},
{162, 163},
{162, 164},
{162, 167},
{162, 241},
{162, 260},
{162, 261},
{162, 264},
{163, 177},
{163, 178},
{163, 180},
{163, 182},
{163, 198},
{163, 260},
{163, 261},
{163, 277},
{163, 280},
{164, 165},
{164, 166},
{164, 167},
{165, 166},
{165, 167},
{165, 168},
{165, 171},
{165, 184},
{165, 186},
{165, 188},
{166, 167},
{166, 168},
{166, 171},
{166, 245},
{166, 264},
{166, 265},
{166, 268},
{167, 182},
{167, 184},
{167, 186},
{167, 261},
{167, 264},
{167, 265},
{167, 284},
{168, 169},
{168, 170},
{168, 171},
{169, 170},
{169, 171},
{169, 172},
{169, 175},
{169, 188},
{169, 190},
{169, 192},
{170, 171},
{170, 172},
{170, 175},
{170, 249},
{170, 268},
{170, 269},
{170, 272},
{171, 186},
{171, 188},
{171, 190},
{171, 265},
{171, 268},
{171, 269},
{171, 288},
{172, 173},
{172, 174},
{172, 175},
{173, 174},
{173, 175},
{173, 176},
{173, 179},
{173, 192},
{173, 194},
{173, 196},
{174, 175},
{174, 176},
{174, 179},
{174, 253},
{174, 272},
{174, 273},
{174, 276},
{175, 190},
{175, 192},
{175, 194},
{175, 269},
{175, 272},
{175, 273},
{175, 292},
{176, 177},
{176, 178},
{176, 179},
{177, 178},
{177, 179},
{177, 180},
{177, 196},
{177, 198},
{178, 179},
{178, 257},
{178, 260},
{178, 276},
{178, 277},
{179, 194},
{179, 196},
{179, 198},
{179, 273},
{179, 276},
{179, 277},
{179, 296},
{180, 181},
{180, 182},
{180, 183},
{180, 197},
{180, 198},
{181, 182},
{181, 183},
{181, 184},
{181, 187},
{182, 183},
{182, 184},
{182, 187},
{182, 261},
{182, 280},
{182, 281},
{182, 284},
{183, 197},
{183, 198},
{183, 200},
{183, 280},
{183, 281},
{183, 297},
{184, 185},
{184, 186},
{184, 187},
{185, 186},
{185, 187},
{185, 188},
{185, 191},
{186, 187},
{186, 188},
{186, 191},
{186, 265},
{186, 284},
{186, 285},
{186, 288},
{187, 204},
{187, 281},
{187, 284},
{187, 285},
{188, 189},
{188, 190},
{188, 191},
{189, 190},
{189, 191},
{189, 192},
{189, 195},
{190, 191},
{190, 192},
{190, 195},
{190, 269},
{190, 288},
{190, 289},
{190, 292},
{191, 208},
{191, 285},
{191, 288},
{191, 289},
{192, 193},
{192, 194},
{192, 195},
{193, 194},
{193, 195},
{193, 196},
{193, 199},
{194, 195},
{194, 196},
{194, 199},
{194, 273},
{194, 292},
{194, 293},
{194, 296},
{195, 212},
{195, 289},
{195, 292},
{195, 293},
{196, 197},
{196, 198},
{196, 199},
{197, 198},
{197, 199},
{198, 199},
{198, 277},
{198, 280},
{198, 296},
{198, 297},
{199, 216},
{199, 293},
{199, 296},
{199, 297},
{200, 201},
{200, 202},
{200, 203},
{200, 217},
{200, 218},
{200, 281},
{200, 283},
{200, 297},
{201, 202},
{201, 203},
{201, 204},
{201, 207},
{201, 220},
{201, 222},
{201, 224},
{202, 203},
{202, 204},
{202, 207},
{202, 281},
{202, 283},
{202, 287},
{203, 217},
{203, 218},
{203, 220},
{203, 222},
{203, 238},
{204, 205},
{204, 206},
{204, 207},
{204, 281},
{204, 285},
{204, 287},
{205, 206},
{205, 207},
{205, 208},
{205, 211},
{205, 224},
{205, 226},
{205, 228},
{206, 207},
{206, 208},
{206, 211},
{206, 285},
{206, 287},
{206, 291},
{207, 222},
{207, 224},
{207, 226},
{208, 209},
{208, 210},
{208, 211},
{208, 285},
{208, 289},
{208, 291},
{209, 210},
{209, 211},
{209, 212},
{209, 215},
{209, 228},
{209, 230},
{209, 232},
{210, 211},
{210, 212},
{210, 215},
{210, 289},
{210, 291},
{210, 295},
{211, 226},
{211, 228},
{211, 230},
{212, 213},
{212, 214},
{212, 215},
{212, 289},
{212, 293},
{212, 295},
{213, 214},
{213, 215},
{213, 216},
{213, 219},
{213, 232},
{213, 234},
{213, 236},
{214, 215},
{214, 216},
{214, 219},
{214, 293},
{214, 295},
{214, 299},
{215, 230},
{215, 232},
{215, 234},
{216, 217},
{216, 218},
{216, 219},
{216, 293},
{216, 297},
{216, 299},
{217, 218},
{217, 219},
{217, 220},
{217, 236},
{217, 238},
{218, 219},
{218, 283},
{218, 297},
{218, 299},
{219, 234},
{219, 236},
{219, 238},
{220, 221},
{220, 222},
{220, 223},
{220, 237},
{220, 238},
{221, 222},
{221, 223},
{221, 224},
{221, 227},
{221, 240},
{221, 242},
{221, 244},
{222, 223},
{222, 224},
{222, 227},
{223, 237},
{223, 238},
{223, 240},
{223, 242},
{223, 258},
{224, 225},
{224, 226},
{224, 227},
{225, 226},
{225, 227},
{225, 228},
{225, 231},
{225, 244},
{225, 246},
{225, 248},
{226, 227},
{226, 228},
{226, 231},
{227, 242},
{227, 244},
{227, 246},
{228, 229},
{228, 230},
{228, 231},
{229, 230},
{229, 231},
{229, 232},
{229, 235},
{229, 248},
{229, 250},
{229, 252},
{230, 231},
{230, 232},
{230, 235},
{231, 246},
{231, 248},
{231, 250},
{232, 233},
{232, 234},
{232, 235},
{233, 234},
{233, 235},
{233, 236},
{233, 239},
{233, 252},
{233, 254},
{233, 256},
{234, 235},
{234, 236},
{234, 239},
{235, 250},
{235, 252},
{235, 254},
{236, 237},
{236, 238},
{236, 239},
{237, 238},
{237, 239},
{237, 240},
{237, 256},
{237, 258},
{238, 239},
{239, 254},
{239, 256},
{239, 258},
{240, 241},
{240, 242},
{240, 243},
{240, 257},
{240, 258},
{241, 242},
{241, 243},
{241, 244},
{241, 247},
{241, 260},
{241, 262},
{241, 264},
{242, 243},
{242, 244},
{242, 247},
{243, 257},
{243, 258},
{243, 260},
{243, 262},
{243, 278},
{244, 245},
{244, 246},
{244, 247},
{245, 246},
{245, 247},
{245, 248},
{245, 251},
{245, 264},
{245, 266},
{245, 268},
{246, 247},
{246, 248},
{246, 251},
{247, 262},
{247, 264},
{247, 266},
{248, 249},
{248, 250},
{248, 251},
{249, 250},
{249, 251},
{249, 252},
{249, 255},
{249, 268},
{249, 270},
{249, 272},
{250, 251},
{250, 252},
{250, 255},
{251, 266},
{251, 268},
{251, 270},
{252, 253},
{252, 254},
{252, 255},
{253, 254},
{253, 255},
{253, 256},
{253, 259},
{253, 272},
{253, 274},
{253, 276},
{254, 255},
{254, 256},
{254, 259},
{255, 270},
{255, 272},
{255, 274},
{256, 257},
{256, 258},
{256, 259},
{257, 258},
{257, 259},
{257, 260},
{257, 276},
{257, 278},
{258, 259},
{259, 274},
{259, 276},
{259, 278},
{260, 261},
{260, 262},
{260, 263},
{260, 277},
{260, 278},
{261, 262},
{261, 263},
{261, 264},
{261, 267},
{261, 280},
{261, 282},
{261, 284},
{262, 263},
{262, 264},
{262, 267},
{263, 277},
{263, 278},
{263, 280},
{263, 282},
{263, 298},
{264, 265},
{264, 266},
{264, 267},
{265, 266},
{265, 267},
{265, 268},
{265, 271},
{265, 284},
{265, 286},
{265, 288},
{266, 267},
{266, 268},
{266, 271},
{267, 282},
{267, 284},
{267, 286},
{268, 269},
{268, 270},
{268, 271},
{269, 270},
{269, 271},
{269, 272},
{269, 275},
{269, 288},
{269, 290},
{269, 292},
{270, 271},
{270, 272},
{270, 275},
{271, 286},
{271, 288},
{271, 290},
{272, 273},
{272, 274},
{272, 275},
{273, 274},
{273, 275},
{273, 276},
{273, 279},
{273, 292},
{273, 294},
{273, 296},
{274, 275},
{274, 276},
{274, 279},
{275, 290},
{275, 292},
{275, 294},
{276, 277},
{276, 278},
{276, 279},
{277, 278},
{277, 279},
{277, 280},
{277, 296},
{277, 298},
{278, 279},
{279, 294},
{279, 296},
{279, 298},
{280, 281},
{280, 282},
{280, 283},
{280, 297},
{280, 298},
{281, 282},
{281, 283},
{281, 284},
{281, 287},
{282, 283},
{282, 284},
{282, 287},
{283, 297},
{283, 298},
{284, 285},
{284, 286},
{284, 287},
{285, 286},
{285, 287},
{285, 288},
{285, 291},
{286, 287},
{286, 288},
{286, 291},
{288, 289},
{288, 290},
{288, 291},
{289, 290},
{289, 291},
{289, 292},
{289, 295},
{290, 291},
{290, 292},
{290, 295},
{292, 293},
{292, 294},
{292, 295},
{293, 294},
{293, 295},
{293, 296},
{293, 299},
{294, 295},
{294, 296},
{294, 299},
{296, 297},
{296, 298},
{296, 299},
{297, 298},
{297, 299},
{298, 299}
};
positions[ 0] = Vec3( 1.000000, 0.100000, 0.100000);
positions[ 1] = Vec3( 1.000000, 0.300000, 0.300000);
positions[ 2] = Vec3( 1.200000, 0.100000, 0.300000);
positions[ 3] = Vec3( 1.200000, 0.300000, 0.100000);
positions[ 4] = Vec3( 1.000000, 0.100000, 0.500000);
positions[ 5] = Vec3( 1.000000, 0.300000, 0.700000);
positions[ 6] = Vec3( 1.200000, 0.100000, 0.700000);
positions[ 7] = Vec3( 1.200000, 0.300000, 0.500000);
positions[ 8] = Vec3( 1.000000, 0.100000, 0.900000);
positions[ 9] = Vec3( 1.000000, 0.300000, 1.100000);
positions[ 10] = Vec3( 1.200000, 0.100000, 1.100000);
positions[ 11] = Vec3( 1.200000, 0.300000, 0.900000);
positions[ 12] = Vec3( 1.000000, 0.100000, 1.300000);
positions[ 13] = Vec3( 1.000000, 0.300000, 1.500000);
positions[ 14] = Vec3( 1.200000, 0.100000, 1.500000);
positions[ 15] = Vec3( 1.200000, 0.300000, 1.300000);
positions[ 16] = Vec3( 1.000000, 0.100000, 1.700000);
positions[ 17] = Vec3( 1.000000, 0.300000, 1.900000);
positions[ 18] = Vec3( 1.200000, 0.100000, 1.900000);
positions[ 19] = Vec3( 1.200000, 0.300000, 1.700000);
positions[ 20] = Vec3( 1.000000, 0.500000, 0.100000);
positions[ 21] = Vec3( 1.000000, 0.700000, 0.300000);
positions[ 22] = Vec3( 1.200000, 0.500000, 0.300000);
positions[ 23] = Vec3( 1.200000, 0.700000, 0.100000);
positions[ 24] = Vec3( 1.000000, 0.500000, 0.500000);
positions[ 25] = Vec3( 1.000000, 0.700000, 0.700000);
positions[ 26] = Vec3( 1.200000, 0.500000, 0.700000);
positions[ 27] = Vec3( 1.200000, 0.700000, 0.500000);
positions[ 28] = Vec3( 1.000000, 0.500000, 0.900000);
positions[ 29] = Vec3( 1.000000, 0.700000, 1.100000);
positions[ 30] = Vec3( 1.200000, 0.500000, 1.100000);
positions[ 31] = Vec3( 1.200000, 0.700000, 0.900000);
positions[ 32] = Vec3( 1.000000, 0.500000, 1.300000);
positions[ 33] = Vec3( 1.000000, 0.700000, 1.500000);
positions[ 34] = Vec3( 1.200000, 0.500000, 1.500000);
positions[ 35] = Vec3( 1.200000, 0.700000, 1.300000);
positions[ 36] = Vec3( 1.000000, 0.500000, 1.700000);
positions[ 37] = Vec3( 1.000000, 0.700000, 1.900000);
positions[ 38] = Vec3( 1.200000, 0.500000, 1.900000);
positions[ 39] = Vec3( 1.200000, 0.700000, 1.700000);
positions[ 40] = Vec3( 1.000000, 0.900000, 0.100000);
positions[ 41] = Vec3( 1.000000, 1.100000, 0.300000);
positions[ 42] = Vec3( 1.200000, 0.900000, 0.300000);
positions[ 43] = Vec3( 1.200000, 1.100000, 0.100000);
positions[ 44] = Vec3( 1.000000, 0.900000, 0.500000);
positions[ 45] = Vec3( 1.000000, 1.100000, 0.700000);
positions[ 46] = Vec3( 1.200000, 0.900000, 0.700000);
positions[ 47] = Vec3( 1.200000, 1.100000, 0.500000);
positions[ 48] = Vec3( 1.000000, 0.900000, 0.900000);
positions[ 49] = Vec3( 1.000000, 1.100000, 1.100000);
positions[ 50] = Vec3( 1.200000, 0.900000, 1.100000);
positions[ 51] = Vec3( 1.200000, 1.100000, 0.900000);
positions[ 52] = Vec3( 1.000000, 0.900000, 1.300000);
positions[ 53] = Vec3( 1.000000, 1.100000, 1.500000);
positions[ 54] = Vec3( 1.200000, 0.900000, 1.500000);
positions[ 55] = Vec3( 1.200000, 1.100000, 1.300000);
positions[ 56] = Vec3( 1.000000, 0.900000, 1.700000);
positions[ 57] = Vec3( 1.000000, 1.100000, 1.900000);
positions[ 58] = Vec3( 1.200000, 0.900000, 1.900000);
positions[ 59] = Vec3( 1.200000, 1.100000, 1.700000);
positions[ 60] = Vec3( 1.000000, 1.300000, 0.100000);
positions[ 61] = Vec3( 1.000000, 1.500000, 0.300000);
positions[ 62] = Vec3( 1.200000, 1.300000, 0.300000);
positions[ 63] = Vec3( 1.200000, 1.500000, 0.100000);
positions[ 64] = Vec3( 1.000000, 1.300000, 0.500000);
positions[ 65] = Vec3( 1.000000, 1.500000, 0.700000);
positions[ 66] = Vec3( 1.200000, 1.300000, 0.700000);
positions[ 67] = Vec3( 1.200000, 1.500000, 0.500000);
positions[ 68] = Vec3( 1.000000, 1.300000, 0.900000);
positions[ 69] = Vec3( 1.000000, 1.500000, 1.100000);
positions[ 70] = Vec3( 1.200000, 1.300000, 1.100000);
positions[ 71] = Vec3( 1.200000, 1.500000, 0.900000);
positions[ 72] = Vec3( 1.000000, 1.300000, 1.300000);
positions[ 73] = Vec3( 1.000000, 1.500000, 1.500000);
positions[ 74] = Vec3( 1.200000, 1.300000, 1.500000);
positions[ 75] = Vec3( 1.200000, 1.500000, 1.300000);
positions[ 76] = Vec3( 1.000000, 1.300000, 1.700000);
positions[ 77] = Vec3( 1.000000, 1.500000, 1.900000);
positions[ 78] = Vec3( 1.200000, 1.300000, 1.900000);
positions[ 79] = Vec3( 1.200000, 1.500000, 1.700000);
positions[ 80] = Vec3( 1.000000, 1.700000, 0.100000);
positions[ 81] = Vec3( 1.000000, 1.900000, 0.300000);
positions[ 82] = Vec3( 1.200000, 1.700000, 0.300000);
positions[ 83] = Vec3( 1.200000, 1.900000, 0.100000);
positions[ 84] = Vec3( 1.000000, 1.700000, 0.500000);
positions[ 85] = Vec3( 1.000000, 1.900000, 0.700000);
positions[ 86] = Vec3( 1.200000, 1.700000, 0.700000);
positions[ 87] = Vec3( 1.200000, 1.900000, 0.500000);
positions[ 88] = Vec3( 1.000000, 1.700000, 0.900000);
positions[ 89] = Vec3( 1.000000, 1.900000, 1.100000);
positions[ 90] = Vec3( 1.200000, 1.700000, 1.100000);
positions[ 91] = Vec3( 1.200000, 1.900000, 0.900000);
positions[ 92] = Vec3( 1.000000, 1.700000, 1.300000);
positions[ 93] = Vec3( 1.000000, 1.900000, 1.500000);
positions[ 94] = Vec3( 1.200000, 1.700000, 1.500000);
positions[ 95] = Vec3( 1.200000, 1.900000, 1.300000);
positions[ 96] = Vec3( 1.000000, 1.700000, 1.700000);
positions[ 97] = Vec3( 1.000000, 1.900000, 1.900000);
positions[ 98] = Vec3( 1.200000, 1.700000, 1.900000);
positions[ 99] = Vec3( 1.200000, 1.900000, 1.700000);
positions[100] = Vec3( 1.400000, 0.100000, 0.100000);
positions[101] = Vec3( 1.400000, 0.300000, 0.300000);
positions[102] = Vec3( 1.600000, 0.100000, 0.300000);
positions[103] = Vec3( 1.600000, 0.300000, 0.100000);
positions[104] = Vec3( 1.400000, 0.100000, 0.500000);
positions[105] = Vec3( 1.400000, 0.300000, 0.700000);
positions[106] = Vec3( 1.600000, 0.100000, 0.700000);
positions[107] = Vec3( 1.600000, 0.300000, 0.500000);
positions[108] = Vec3( 1.400000, 0.100000, 0.900000);
positions[109] = Vec3( 1.400000, 0.300000, 1.100000);
positions[110] = Vec3( 1.600000, 0.100000, 1.100000);
positions[111] = Vec3( 1.600000, 0.300000, 0.900000);
positions[112] = Vec3( 1.400000, 0.100000, 1.300000);
positions[113] = Vec3( 1.400000, 0.300000, 1.500000);
positions[114] = Vec3( 1.600000, 0.100000, 1.500000);
positions[115] = Vec3( 1.600000, 0.300000, 1.300000);
positions[116] = Vec3( 1.400000, 0.100000, 1.700000);
positions[117] = Vec3( 1.400000, 0.300000, 1.900000);
positions[118] = Vec3( 1.600000, 0.100000, 1.900000);
positions[119] = Vec3( 1.600000, 0.300000, 1.700000);
positions[120] = Vec3( 1.400000, 0.500000, 0.100000);
positions[121] = Vec3( 1.400000, 0.700000, 0.300000);
positions[122] = Vec3( 1.600000, 0.500000, 0.300000);
positions[123] = Vec3( 1.600000, 0.700000, 0.100000);
positions[124] = Vec3( 1.400000, 0.500000, 0.500000);
positions[125] = Vec3( 1.400000, 0.700000, 0.700000);
positions[126] = Vec3( 1.600000, 0.500000, 0.700000);
positions[127] = Vec3( 1.600000, 0.700000, 0.500000);
positions[128] = Vec3( 1.400000, 0.500000, 0.900000);
positions[129] = Vec3( 1.400000, 0.700000, 1.100000);
positions[130] = Vec3( 1.600000, 0.500000, 1.100000);
positions[131] = Vec3( 1.600000, 0.700000, 0.900000);
positions[132] = Vec3( 1.400000, 0.500000, 1.300000);
positions[133] = Vec3( 1.400000, 0.700000, 1.500000);
positions[134] = Vec3( 1.600000, 0.500000, 1.500000);
positions[135] = Vec3( 1.600000, 0.700000, 1.300000);
positions[136] = Vec3( 1.400000, 0.500000, 1.700000);
positions[137] = Vec3( 1.400000, 0.700000, 1.900000);
positions[138] = Vec3( 1.600000, 0.500000, 1.900000);
positions[139] = Vec3( 1.600000, 0.700000, 1.700000);
positions[140] = Vec3( 1.400000, 0.900000, 0.100000);
positions[141] = Vec3( 1.400000, 1.100000, 0.300000);
positions[142] = Vec3( 1.600000, 0.900000, 0.300000);
positions[143] = Vec3( 1.600000, 1.100000, 0.100000);
positions[144] = Vec3( 1.400000, 0.900000, 0.500000);
positions[145] = Vec3( 1.400000, 1.100000, 0.700000);
positions[146] = Vec3( 1.600000, 0.900000, 0.700000);
positions[147] = Vec3( 1.600000, 1.100000, 0.500000);
positions[148] = Vec3( 1.400000, 0.900000, 0.900000);
positions[149] = Vec3( 1.400000, 1.100000, 1.100000);
positions[150] = Vec3( 1.600000, 0.900000, 1.100000);
positions[151] = Vec3( 1.600000, 1.100000, 0.900000);
positions[152] = Vec3( 1.400000, 0.900000, 1.300000);
positions[153] = Vec3( 1.400000, 1.100000, 1.500000);
positions[154] = Vec3( 1.600000, 0.900000, 1.500000);
positions[155] = Vec3( 1.600000, 1.100000, 1.300000);
positions[156] = Vec3( 1.400000, 0.900000, 1.700000);
positions[157] = Vec3( 1.400000, 1.100000, 1.900000);
positions[158] = Vec3( 1.600000, 0.900000, 1.900000);
positions[159] = Vec3( 1.600000, 1.100000, 1.700000);
positions[160] = Vec3( 1.400000, 1.300000, 0.100000);
positions[161] = Vec3( 1.400000, 1.500000, 0.300000);
positions[162] = Vec3( 1.600000, 1.300000, 0.300000);
positions[163] = Vec3( 1.600000, 1.500000, 0.100000);
positions[164] = Vec3( 1.400000, 1.300000, 0.500000);
positions[165] = Vec3( 1.400000, 1.500000, 0.700000);
positions[166] = Vec3( 1.600000, 1.300000, 0.700000);
positions[167] = Vec3( 1.600000, 1.500000, 0.500000);
positions[168] = Vec3( 1.400000, 1.300000, 0.900000);
positions[169] = Vec3( 1.400000, 1.500000, 1.100000);
positions[170] = Vec3( 1.600000, 1.300000, 1.100000);
positions[171] = Vec3( 1.600000, 1.500000, 0.900000);
positions[172] = Vec3( 1.400000, 1.300000, 1.300000);
positions[173] = Vec3( 1.400000, 1.500000, 1.500000);
positions[174] = Vec3( 1.600000, 1.300000, 1.500000);
positions[175] = Vec3( 1.600000, 1.500000, 1.300000);
positions[176] = Vec3( 1.400000, 1.300000, 1.700000);
positions[177] = Vec3( 1.400000, 1.500000, 1.900000);
positions[178] = Vec3( 1.600000, 1.300000, 1.900000);
positions[179] = Vec3( 1.600000, 1.500000, 1.700000);
positions[180] = Vec3( 1.400000, 1.700000, 0.100000);
positions[181] = Vec3( 1.400000, 1.900000, 0.300000);
positions[182] = Vec3( 1.600000, 1.700000, 0.300000);
positions[183] = Vec3( 1.600000, 1.900000, 0.100000);
positions[184] = Vec3( 1.400000, 1.700000, 0.500000);
positions[185] = Vec3( 1.400000, 1.900000, 0.700000);
positions[186] = Vec3( 1.600000, 1.700000, 0.700000);
positions[187] = Vec3( 1.600000, 1.900000, 0.500000);
positions[188] = Vec3( 1.400000, 1.700000, 0.900000);
positions[189] = Vec3( 1.400000, 1.900000, 1.100000);
positions[190] = Vec3( 1.600000, 1.700000, 1.100000);
positions[191] = Vec3( 1.600000, 1.900000, 0.900000);
positions[192] = Vec3( 1.400000, 1.700000, 1.300000);
positions[193] = Vec3( 1.400000, 1.900000, 1.500000);
positions[194] = Vec3( 1.600000, 1.700000, 1.500000);
positions[195] = Vec3( 1.600000, 1.900000, 1.300000);
positions[196] = Vec3( 1.400000, 1.700000, 1.700000);
positions[197] = Vec3( 1.400000, 1.900000, 1.900000);
positions[198] = Vec3( 1.600000, 1.700000, 1.900000);
positions[199] = Vec3( 1.600000, 1.900000, 1.700000);
positions[200] = Vec3( 1.800000, 0.100000, 0.100000);
positions[201] = Vec3( 1.800000, 0.300000, 0.300000);
positions[202] = Vec3( 2.000000, 0.100000, 0.300000);
positions[203] = Vec3( 2.000000, 0.300000, 0.100000);
positions[204] = Vec3( 1.800000, 0.100000, 0.500000);
positions[205] = Vec3( 1.800000, 0.300000, 0.700000);
positions[206] = Vec3( 2.000000, 0.100000, 0.700000);
positions[207] = Vec3( 2.000000, 0.300000, 0.500000);
positions[208] = Vec3( 1.800000, 0.100000, 0.900000);
positions[209] = Vec3( 1.800000, 0.300000, 1.100000);
positions[210] = Vec3( 2.000000, 0.100000, 1.100000);
positions[211] = Vec3( 2.000000, 0.300000, 0.900000);
positions[212] = Vec3( 1.800000, 0.100000, 1.300000);
positions[213] = Vec3( 1.800000, 0.300000, 1.500000);
positions[214] = Vec3( 2.000000, 0.100000, 1.500000);
positions[215] = Vec3( 2.000000, 0.300000, 1.300000);
positions[216] = Vec3( 1.800000, 0.100000, 1.700000);
positions[217] = Vec3( 1.800000, 0.300000, 1.900000);
positions[218] = Vec3( 2.000000, 0.100000, 1.900000);
positions[219] = Vec3( 2.000000, 0.300000, 1.700000);
positions[220] = Vec3( 1.800000, 0.500000, 0.100000);
positions[221] = Vec3( 1.800000, 0.700000, 0.300000);
positions[222] = Vec3( 2.000000, 0.500000, 0.300000);
positions[223] = Vec3( 2.000000, 0.700000, 0.100000);
positions[224] = Vec3( 1.800000, 0.500000, 0.500000);
positions[225] = Vec3( 1.800000, 0.700000, 0.700000);
positions[226] = Vec3( 2.000000, 0.500000, 0.700000);
positions[227] = Vec3( 2.000000, 0.700000, 0.500000);
positions[228] = Vec3( 1.800000, 0.500000, 0.900000);
positions[229] = Vec3( 1.800000, 0.700000, 1.100000);
positions[230] = Vec3( 2.000000, 0.500000, 1.100000);
positions[231] = Vec3( 2.000000, 0.700000, 0.900000);
positions[232] = Vec3( 1.800000, 0.500000, 1.300000);
positions[233] = Vec3( 1.800000, 0.700000, 1.500000);
positions[234] = Vec3( 2.000000, 0.500000, 1.500000);
positions[235] = Vec3( 2.000000, 0.700000, 1.300000);
positions[236] = Vec3( 1.800000, 0.500000, 1.700000);
positions[237] = Vec3( 1.800000, 0.700000, 1.900000);
positions[238] = Vec3( 2.000000, 0.500000, 1.900000);
positions[239] = Vec3( 2.000000, 0.700000, 1.700000);
positions[240] = Vec3( 1.800000, 0.900000, 0.100000);
positions[241] = Vec3( 1.800000, 1.100000, 0.300000);
positions[242] = Vec3( 2.000000, 0.900000, 0.300000);
positions[243] = Vec3( 2.000000, 1.100000, 0.100000);
positions[244] = Vec3( 1.800000, 0.900000, 0.500000);
positions[245] = Vec3( 1.800000, 1.100000, 0.700000);
positions[246] = Vec3( 2.000000, 0.900000, 0.700000);
positions[247] = Vec3( 2.000000, 1.100000, 0.500000);
positions[248] = Vec3( 1.800000, 0.900000, 0.900000);
positions[249] = Vec3( 1.800000, 1.100000, 1.100000);
positions[250] = Vec3( 2.000000, 0.900000, 1.100000);
positions[251] = Vec3( 2.000000, 1.100000, 0.900000);
positions[252] = Vec3( 1.800000, 0.900000, 1.300000);
positions[253] = Vec3( 1.800000, 1.100000, 1.500000);
positions[254] = Vec3( 2.000000, 0.900000, 1.500000);
positions[255] = Vec3( 2.000000, 1.100000, 1.300000);
positions[256] = Vec3( 1.800000, 0.900000, 1.700000);
positions[257] = Vec3( 1.800000, 1.100000, 1.900000);
positions[258] = Vec3( 2.000000, 0.900000, 1.900000);
positions[259] = Vec3( 2.000000, 1.100000, 1.700000);
positions[260] = Vec3( 1.800000, 1.300000, 0.100000);
positions[261] = Vec3( 1.800000, 1.500000, 0.300000);
positions[262] = Vec3( 2.000000, 1.300000, 0.300000);
positions[263] = Vec3( 2.000000, 1.500000, 0.100000);
positions[264] = Vec3( 1.800000, 1.300000, 0.500000);
positions[265] = Vec3( 1.800000, 1.500000, 0.700000);
positions[266] = Vec3( 2.000000, 1.300000, 0.700000);
positions[267] = Vec3( 2.000000, 1.500000, 0.500000);
positions[268] = Vec3( 1.800000, 1.300000, 0.900000);
positions[269] = Vec3( 1.800000, 1.500000, 1.100000);
positions[270] = Vec3( 2.000000, 1.300000, 1.100000);
positions[271] = Vec3( 2.000000, 1.500000, 0.900000);
positions[272] = Vec3( 1.800000, 1.300000, 1.300000);
positions[273] = Vec3( 1.800000, 1.500000, 1.500000);
positions[274] = Vec3( 2.000000, 1.300000, 1.500000);
positions[275] = Vec3( 2.000000, 1.500000, 1.300000);
positions[276] = Vec3( 1.800000, 1.300000, 1.700000);
positions[277] = Vec3( 1.800000, 1.500000, 1.900000);
positions[278] = Vec3( 2.000000, 1.300000, 1.900000);
positions[279] = Vec3( 2.000000, 1.500000, 1.700000);
positions[280] = Vec3( 1.800000, 1.700000, 0.100000);
positions[281] = Vec3( 1.800000, 1.900000, 0.300000);
positions[282] = Vec3( 2.000000, 1.700000, 0.300000);
positions[283] = Vec3( 2.000000, 1.900000, 0.100000);
positions[284] = Vec3( 1.800000, 1.700000, 0.500000);
positions[285] = Vec3( 1.800000, 1.900000, 0.700000);
positions[286] = Vec3( 2.000000, 1.700000, 0.700000);
positions[287] = Vec3( 2.000000, 1.900000, 0.500000);
positions[288] = Vec3( 1.800000, 1.700000, 0.900000);
positions[289] = Vec3( 1.800000, 1.900000, 1.100000);
positions[290] = Vec3( 2.000000, 1.700000, 1.100000);
positions[291] = Vec3( 2.000000, 1.900000, 0.900000);
positions[292] = Vec3( 1.800000, 1.700000, 1.300000);
positions[293] = Vec3( 1.800000, 1.900000, 1.500000);
positions[294] = Vec3( 2.000000, 1.700000, 1.500000);
positions[295] = Vec3( 2.000000, 1.900000, 1.300000);
positions[296] = Vec3( 1.800000, 1.700000, 1.700000);
positions[297] = Vec3( 1.800000, 1.900000, 1.900000);
positions[298] = Vec3( 2.000000, 1.700000, 1.900000);
positions[299] = Vec3( 2.000000, 1.900000, 1.700000);
positions[300] = Vec3( 2.951107, -3.362521, 2.059732);
positions[301] = Vec3( 2.972431, -3.382932, 1.964188);
positions[302] = Vec3( 2.920649, -3.445972, 2.105648);
positions[303] = Vec3( 0.662642, -5.332964, 2.226078);
positions[304] = Vec3( 0.568036, -5.327616, 2.258033);
positions[305] = Vec3( 0.713693, -5.396871, 2.283608);
positions[306] = Vec3( 0.375979, 1.453051, 4.357184);
positions[307] = Vec3( 0.437414, 1.435204, 4.434042);
positions[308] = Vec3( 0.396798, 1.389884, 4.282508);
positions[309] = Vec3( 0.719729, -1.698267, 3.799088);
positions[310] = Vec3( 0.764919, -1.782256, 3.829148);
positions[311] = Vec3( 0.646168, -1.675347, 3.862833);
positions[312] = Vec3( 2.452188, -0.779126, -2.537916);
positions[313] = Vec3( 2.496232, -0.830907, -2.464575);
positions[314] = Vec3( 2.390716, -0.839288, -2.588923);
positions[315] = Vec3( 0.044700, -1.803381, 1.938277);
positions[316] = Vec3( 0.005621, -1.743210, 1.868619);
positions[317] = Vec3(-0.027822, -1.859181, 1.978612);
positions[318] = Vec3( 2.599217, 4.089409, -2.985284);
positions[319] = Vec3( 2.663697, 4.012986, -2.986663);
positions[320] = Vec3( 2.641914, 4.168248, -2.940998);
positions[321] = Vec3( 2.352417, 0.187708, 3.348698);
positions[322] = Vec3( 2.325516, 0.241024, 3.268488);
positions[323] = Vec3( 2.434600, 0.134813, 3.327530);
positions[324] = Vec3( 2.933102, 4.064756, 0.481577);
positions[325] = Vec3( 2.945198, 3.985112, 0.422327);
positions[326] = Vec3( 3.008118, 4.068904, 0.547573);
positions[327] = Vec3( 2.320049, 0.576773, 2.568733);
positions[328] = Vec3( 2.303630, 0.485092, 2.605135);
positions[329] = Vec3( 2.341333, 0.570600, 2.471220);
positions[330] = Vec3(-0.667248, -3.852591, 0.238265);
positions[331] = Vec3(-0.657486, -3.893804, 0.328853);
positions[332] = Vec3(-0.649045, -3.754439, 0.244163);
positions[333] = Vec3(-0.011692, -3.981454, 9.383976);
positions[334] = Vec3(-0.072196, -4.060434, 9.373912);
positions[335] = Vec3( 0.075141, -3.999906, 9.337938);
positions[336] = Vec3(-0.456406, -7.665643, 4.384540);
positions[337] = Vec3(-0.524595, -7.673748, 4.457236);
positions[338] = Vec3(-0.424694, -7.570967, 4.378992);
positions[339] = Vec3( 2.278955, 0.833744, 4.563679);
positions[340] = Vec3( 2.288718, 0.734273, 4.560474);
positions[341] = Vec3( 2.274489, 0.869815, 4.470518);
positions[342] = Vec3( 2.222185, -4.546379, 2.625584);
positions[343] = Vec3( 2.213037, -4.589846, 2.715178);
positions[344] = Vec3( 2.220659, -4.616433, 2.554239);
positions[345] = Vec3( 0.354099, 4.504220, 1.021600);
positions[346] = Vec3( 0.357623, 4.602412, 1.040198);
positions[347] = Vec3( 0.446870, 4.469583, 1.007672);
positions[348] = Vec3( 0.457101, -2.938576, 7.215448);
positions[349] = Vec3( 0.545515, -2.941997, 7.262045);
positions[350] = Vec3( 0.471169, -2.945717, 7.116701);
positions[351] = Vec3( 3.032895, 1.485529, 4.654941);
positions[352] = Vec3( 2.967757, 1.547590, 4.611290);
positions[353] = Vec3( 3.072310, 1.424721, 4.586029);
positions[354] = Vec3(-0.234464, 6.451316, 2.101790);
positions[355] = Vec3(-0.254907, 6.355916, 2.123720);
positions[356] = Vec3(-0.268606, 6.510379, 2.174905);
positions[357] = Vec3( 0.190961, -1.700393, -2.959010);
positions[358] = Vec3( 0.255712, -1.774887, -2.942947);
positions[359] = Vec3( 0.241194, -1.616516, -2.980016);
positions[360] = Vec3( 0.045530, -2.135936, -1.927923);
positions[361] = Vec3( 0.068877, -2.185568, -1.844307);
positions[362] = Vec3(-0.045446, -2.095531, -1.918401);
positions[363] = Vec3( 0.606526, -8.663856, 0.520287);
positions[364] = Vec3( 0.633190, -8.635260, 0.612326);
positions[365] = Vec3( 0.667816, -8.736345, 0.488839);
positions[366] = Vec3( 0.399390, -4.826147, -3.430496);
positions[367] = Vec3( 0.472803, -4.766929, -3.463718);
positions[368] = Vec3( 0.395045, -4.908653, -3.486833);
positions[369] = Vec3(-0.437018, -0.510065, 4.768019);
positions[370] = Vec3(-0.466594, -0.542268, 4.857954);
positions[371] = Vec3(-0.445858, -0.584208, 4.701501);
positions[372] = Vec3( 0.511983, 2.509608, -0.559217);
positions[373] = Vec3( 0.600775, 2.512712, -0.513322);
positions[374] = Vec3( 0.506194, 2.426846, -0.615047);
positions[375] = Vec3( 0.712909, -2.217362, 5.969456);
positions[376] = Vec3( 0.747185, -2.311274, 5.971859);
positions[377] = Vec3( 0.753564, -2.169015, 5.891934);
positions[378] = Vec3( 0.188865, 0.416177, 2.591054);
positions[379] = Vec3( 0.204430, 0.499285, 2.644446);
positions[380] = Vec3( 0.243256, 0.341409, 2.629151);
positions[381] = Vec3(-0.000369, -0.651951, 6.239346);
positions[382] = Vec3( 0.065439, -0.676234, 6.310618);
positions[383] = Vec3( 0.044188, -0.656373, 6.149931);
positions[384] = Vec3( 2.712668, -1.182957, 4.389050);
positions[385] = Vec3( 2.812275, -1.190709, 4.384770);
positions[386] = Vec3( 2.680979, -1.210314, 4.479865);
positions[387] = Vec3(-0.696201, 3.022133, -2.679026);
positions[388] = Vec3(-0.747410, 3.071712, -2.749165);
positions[389] = Vec3(-0.674800, 2.930219, -2.712100);
positions[390] = Vec3( 0.758934, -0.875066, 5.334662);
positions[391] = Vec3( 0.723683, -0.967745, 5.321699);
positions[392] = Vec3( 0.776218, -0.833206, 5.245505);
positions[393] = Vec3(-0.730997, -2.480480, -0.066262);
positions[394] = Vec3(-0.794811, -2.440311, -0.131945);
positions[395] = Vec3(-0.637201, -2.459158, -0.093604);
positions[396] = Vec3( 3.115578, -3.229046, 3.215763);
positions[397] = Vec3( 3.088962, -3.293697, 3.287260);
positions[398] = Vec3( 3.140152, -3.141525, 3.257432);
positions[399] = Vec3(-0.423054, 4.254694, 2.784431);
positions[400] = Vec3(-0.387732, 4.200406, 2.860622);
positions[401] = Vec3(-0.360331, 4.248001, 2.706836);
positions[402] = Vec3( 2.257664, -2.055041, 4.737440);
positions[403] = Vec3( 2.293765, -2.059440, 4.830592);
positions[404] = Vec3( 2.173435, -2.001143, 4.736847);
positions[405] = Vec3(-0.722306, -1.194154, 2.273126);
positions[406] = Vec3(-0.668584, -1.172270, 2.191670);
positions[407] = Vec3(-0.797746, -1.129085, 2.281772);
positions[408] = Vec3( 0.691776, 1.224396, 3.799095);
positions[409] = Vec3( 0.705606, 1.271447, 3.886243);
positions[410] = Vec3( 0.691154, 1.125562, 3.814308);
positions[411] = Vec3(-0.456679, -0.892356, -0.296613);
positions[412] = Vec3(-0.531639, -0.954464, -0.319494);
positions[413] = Vec3(-0.379640, -0.908994, -0.358161);
positions[414] = Vec3( 2.656188, 0.738364, -1.346451);
positions[415] = Vec3( 2.736488, 0.790083, -1.316837);
positions[416] = Vec3( 2.594035, 0.726113, -1.269075);
positions[417] = Vec3( 0.504259, -2.293532, -0.455741);
positions[418] = Vec3( 0.489555, -2.199071, -0.426402);
positions[419] = Vec3( 0.569500, -2.337774, -0.394209);
positions[420] = Vec3( 3.108846, -0.625970, 1.987571);
positions[421] = Vec3( 3.192116, -0.575363, 1.965100);
positions[422] = Vec3( 3.030736, -0.563531, 1.987073);
positions[423] = Vec3(-0.230773, -1.525560, -2.468051);
positions[424] = Vec3(-0.286289, -1.564689, -2.541446);
positions[425] = Vec3(-0.244875, -1.577944, -2.384044);
positions[426] = Vec3( 0.251362, 0.837215, 6.599611);
positions[427] = Vec3( 0.225401, 0.896682, 6.675701);
positions[428] = Vec3( 0.308036, 0.888457, 6.535094);
positions[429] = Vec3( 0.654103, 0.198012, -3.834073);
positions[430] = Vec3( 0.593937, 0.118478, -3.826696);
positions[431] = Vec3( 0.629776, 0.250773, -3.915463);
positions[432] = Vec3( 0.647252, 4.773339, 1.987686);
positions[433] = Vec3( 0.555876, 4.756811, 1.950576);
positions[434] = Vec3( 0.656523, 4.726487, 2.075544);
positions[435] = Vec3( 3.204338, -1.018555, -2.668690);
positions[436] = Vec3( 3.187852, -0.981181, -2.577413);
positions[437] = Vec3( 3.298672, -0.999603, -2.695928);
positions[438] = Vec3(-0.724001, 6.350038, 3.155179);
positions[439] = Vec3(-0.644532, 6.388416, 3.108150);
positions[440] = Vec3(-0.804621, 6.358341, 3.096599);
positions[441] = Vec3( 0.033184, 2.516494, 0.391371);
positions[442] = Vec3( 0.061390, 2.466877, 0.473484);
positions[443] = Vec3( 0.049836, 2.459720, 0.310752);
positions[444] = Vec3(-0.713241, -4.289354, -3.401344);
positions[445] = Vec3(-0.749676, -4.206307, -3.359205);
positions[446] = Vec3(-0.776521, -4.365189, -3.385700);
positions[447] = Vec3( 2.353589, -1.042282, -0.405678);
positions[448] = Vec3( 2.345012, -1.141221, -0.393948);
positions[449] = Vec3( 2.351307, -1.019949, -0.503126);
positions[450] = Vec3( 2.376204, 0.147853, -0.386180);
positions[451] = Vec3( 2.353036, 0.192055, -0.472838);
positions[452] = Vec3( 2.314998, 0.070255, -0.370935);
positions[453] = Vec3(-0.175468, 3.257020, -3.048095);
positions[454] = Vec3(-0.238776, 3.311660, -2.993263);
positions[455] = Vec3(-0.083505, 3.263734, -3.009395);
positions[456] = Vec3( 0.428585, -4.296229, 0.303680);
positions[457] = Vec3( 0.394511, -4.380647, 0.345062);
positions[458] = Vec3( 0.395887, -4.217743, 0.356319);
positions[459] = Vec3( 0.739926, -3.494462, -3.215900);
positions[460] = Vec3( 0.754969, -3.397900, -3.194700);
positions[461] = Vec3( 0.716816, -3.504124, -3.312712);
positions[462] = Vec3(-0.015179, 1.259737, 1.459463);
positions[463] = Vec3(-0.071089, 1.291559, 1.382904);
positions[464] = Vec3(-0.050446, 1.298228, 1.544755);
positions[465] = Vec3( 2.637416, 1.296343, 8.589280);
positions[466] = Vec3( 2.722750, 1.251869, 8.616487);
positions[467] = Vec3( 2.645691, 1.329723, 8.495379);
positions[468] = Vec3( 0.515564, -1.835012, 2.606043);
positions[469] = Vec3( 0.562760, -1.811193, 2.521160);
positions[470] = Vec3( 0.484497, -1.929950, 2.601397);
positions[471] = Vec3( 0.306151, -3.866966, 5.894296);
positions[472] = Vec3( 0.221221, -3.814212, 5.892295);
positions[473] = Vec3( 0.284687, -3.964588, 5.897342);
positions[474] = Vec3( 0.753186, 1.875881, 0.834998);
positions[475] = Vec3( 0.774686, 1.971661, 0.854073);
positions[476] = Vec3( 0.741591, 1.863306, 0.736471);
positions[477] = Vec3(-0.733075, 0.247381, -2.149631);
positions[478] = Vec3(-0.704725, 0.228305, -2.243612);
positions[479] = Vec3(-0.765143, 0.162950, -2.106700);
positions[480] = Vec3( 3.148767, 1.074127, -0.417339);
positions[481] = Vec3( 3.234331, 1.103215, -0.374530);
positions[482] = Vec3( 3.099011, 1.154373, -0.450277);
positions[483] = Vec3(-0.641580, -1.602459, 2.074255);
positions[484] = Vec3(-0.610777, -1.507722, 2.065530);
positions[485] = Vec3(-0.697697, -1.626685, 1.995109);
positions[486] = Vec3( 2.958420, -0.932853, 1.213069);
positions[487] = Vec3( 2.882653, -0.981872, 1.256155);
positions[488] = Vec3( 3.042056, -0.947762, 1.265821);
positions[489] = Vec3( 0.726920, -5.048450, -0.188683);
positions[490] = Vec3( 0.820892, -5.025127, -0.163678);
positions[491] = Vec3( 0.691465, -5.116853, -0.124934);
positions[492] = Vec3( 0.399776, 1.480708, 1.912593);
positions[493] = Vec3( 0.404619, 1.579986, 1.923571);
positions[494] = Vec3( 0.386014, 1.458479, 1.816072);
positions[495] = Vec3( 0.044423, 4.712413, 1.830841);
positions[496] = Vec3(-0.001799, 4.799135, 1.812327);
positions[497] = Vec3( 0.047060, 4.657544, 1.747280);
positions[498] = Vec3( 0.441243, 6.234186, -4.475435);
positions[499] = Vec3( 0.447809, 6.326473, -4.437487);
positions[500] = Vec3( 0.445134, 6.238836, -4.575251);
positions[501] = Vec3( 3.180253, -4.332622, 3.252216);
positions[502] = Vec3( 3.144700, -4.372153, 3.336911);
positions[503] = Vec3( 3.273524, -4.365224, 3.236799);
positions[504] = Vec3(-0.099916, -0.504571, 3.294963);
positions[505] = Vec3(-0.119614, -0.413590, 3.258431);
positions[506] = Vec3(-0.011576, -0.536028, 3.260227);
positions[507] = Vec3( 0.280615, 2.600515, -2.433673);
positions[508] = Vec3( 0.362863, 2.570112, -2.481745);
positions[509] = Vec3( 0.245211, 2.525679, -2.377581);
positions[510] = Vec3( 0.605891, -0.141406, 7.192436);
positions[511] = Vec3( 0.658488, -0.111219, 7.112923);
positions[512] = Vec3( 0.626894, -0.082628, 7.270564);
positions[513] = Vec3(-0.708911, -2.165605, 3.402807);
positions[514] = Vec3(-0.702728, -2.243630, 3.465048);
positions[515] = Vec3(-0.803829, -2.134569, 3.397590);
positions[516] = Vec3(-0.235666, 8.439974, -0.171910);
positions[517] = Vec3(-0.249842, 8.467554, -0.076839);
positions[518] = Vec3(-0.313299, 8.384901, -0.202569);
positions[519] = Vec3(-0.364743, -3.249252, -2.892921);
positions[520] = Vec3(-0.289123, -3.313036, -2.878319);
positions[521] = Vec3(-0.342518, -3.188015, -2.968789);
positions[522] = Vec3(-0.574506, 0.628141, 4.807808);
positions[523] = Vec3(-0.620880, 0.714003, 4.829648);
positions[524] = Vec3(-0.616116, 0.587545, 4.726441);
positions[525] = Vec3(-0.619015, 3.207028, 0.554549);
positions[526] = Vec3(-0.535925, 3.257910, 0.577064);
positions[527] = Vec3(-0.637102, 3.214452, 0.456479);
positions[528] = Vec3(-0.315162, -2.009456, 3.734030);
positions[529] = Vec3(-0.360669, -2.079914, 3.679581);
positions[530] = Vec3(-0.257390, -1.953523, 3.674583);
positions[531] = Vec3( 0.455333, 2.292037, 1.262161);
positions[532] = Vec3( 0.387995, 2.308847, 1.190168);
positions[533] = Vec3( 0.515028, 2.216547, 1.234998);
positions[534] = Vec3(-0.460974, 1.942925, 3.459745);
positions[535] = Vec3(-0.534533, 1.882281, 3.429556);
positions[536] = Vec3(-0.488775, 1.989897, 3.543535);
positions[537] = Vec3( 0.168245, 3.933161, 1.183567);
positions[538] = Vec3( 0.142852, 3.940320, 1.087110);
positions[539] = Vec3( 0.165838, 3.837211, 1.211635);
positions[540] = Vec3(-0.212813, -2.179347, -2.626615);
positions[541] = Vec3(-0.230314, -2.212999, -2.719141);
positions[542] = Vec3(-0.296973, -2.140941, -2.588640);
positions[543] = Vec3( 0.162786, -1.238647, 2.147039);
positions[544] = Vec3( 0.128908, -1.157650, 2.194913);
positions[545] = Vec3( 0.085877, -1.287874, 2.106277);
positions[546] = Vec3( 0.710128, -1.149228, 0.543864);
positions[547] = Vec3( 0.707582, -1.249039, 0.538276);
positions[548] = Vec3( 0.695942, -1.110374, 0.452819);
positions[549] = Vec3( 0.460330, 1.735473, 4.013744);
positions[550] = Vec3( 0.558569, 1.747441, 3.999397);
positions[551] = Vec3( 0.443241, 1.711945, 4.109422);
positions[552] = Vec3(-0.260978, -3.093562, 1.324339);
positions[553] = Vec3(-0.275600, -3.156025, 1.401051);
positions[554] = Vec3(-0.311582, -3.126336, 1.244557);
positions[555] = Vec3( 2.688498, 1.924960, -3.490937);
positions[556] = Vec3( 2.662984, 1.846503, -3.547448);
positions[557] = Vec3( 2.775727, 1.962038, -3.522815);
positions[558] = Vec3( 0.580160, 0.958759, 3.587996);
positions[559] = Vec3( 0.491480, 0.914585, 3.601584);
positions[560] = Vec3( 0.630555, 0.959612, 3.674365);
positions[561] = Vec3( 3.160389, -3.418484, -3.186894);
positions[562] = Vec3( 3.183214, -3.456480, -3.097254);
positions[563] = Vec3( 3.175657, -3.319660, -3.186076);
positions[564] = Vec3( 2.371888, -1.092204, 0.786316);
positions[565] = Vec3( 2.343943, -1.135141, 0.700435);
positions[566] = Vec3( 2.362231, -0.992967, 0.778655);
positions[567] = Vec3( 0.036781, -3.183517, 0.959521);
positions[568] = Vec3( 0.062637, -3.191336, 1.055804);
positions[569] = Vec3(-0.062912, -3.183035, 0.951713);
positions[570] = Vec3( 0.126504, 7.689426, 3.682488);
positions[571] = Vec3( 0.187429, 7.763192, 3.711586);
positions[572] = Vec3( 0.168024, 7.640101, 3.606048);
positions[573] = Vec3( 0.044969, -0.070814, 0.922576);
positions[574] = Vec3( 0.029409, 0.027967, 0.922824);
positions[575] = Vec3( 0.018013, -0.108580, 0.833992);
positions[576] = Vec3(-0.637185, 2.696363, 9.577125);
positions[577] = Vec3(-0.600805, 2.654884, 9.660528);
positions[578] = Vec3(-0.614812, 2.638557, 9.498653);
positions[579] = Vec3( 0.717929, 3.476019, -1.739137);
positions[580] = Vec3( 0.695802, 3.433448, -1.651398);
positions[581] = Vec3( 0.719733, 3.575429, -1.728437);
positions[582] = Vec3(-0.271199, 2.318890, -2.895053);
positions[583] = Vec3(-0.174278, 2.306087, -2.874020);
positions[584] = Vec3(-0.286453, 2.412709, -2.926124);
positions[585] = Vec3(-0.704577, 1.930675, 1.764960);
positions[586] = Vec3(-0.742361, 1.947216, 1.856057);
positions[587] = Vec3(-0.742612, 1.845901, 1.727989);
positions[588] = Vec3( 0.459457, 2.677046, 2.636737);
positions[589] = Vec3( 0.469102, 2.661567, 2.735060);
positions[590] = Vec3( 0.379283, 2.734340, 2.619722);
positions[591] = Vec3( 3.591965, -0.347278, 6.898660);
positions[592] = Vec3( 3.502756, -0.302497, 6.892629);
positions[593] = Vec3( 3.663512, -0.277982, 6.907550);
positions[594] = Vec3( 2.555959, 9.397549, 4.058593);
positions[595] = Vec3( 2.605045, 9.354450, 3.982877);
positions[596] = Vec3( 2.467552, 9.352478, 4.070956);
positions[597] = Vec3( 0.676543, -5.224552, -3.187907);
positions[598] = Vec3( 0.720458, -5.173982, -3.113649);
positions[599] = Vec3( 0.687968, -5.174431, -3.273682);
positions[600] = Vec3(-0.607189, -0.383488, 2.366098);
positions[601] = Vec3(-0.639939, -0.357611, 2.456971);
positions[602] = Vec3(-0.609722, -0.483027, 2.356851);
positions[603] = Vec3( 0.489374, 1.634740, -2.739763);
positions[604] = Vec3( 0.480107, 1.644494, -2.640673);
positions[605] = Vec3( 0.529236, 1.718154, -2.777883);
positions[606] = Vec3(-0.592694, 1.216922, -1.715273);
positions[607] = Vec3(-0.515271, 1.154438, -1.725340);
positions[608] = Vec3(-0.634363, 1.233048, -1.804736);
positions[609] = Vec3(-0.230393, 1.072088, 3.567924);
positions[610] = Vec3(-0.185565, 1.155753, 3.536452);
positions[611] = Vec3(-0.240113, 1.008619, 3.491261);
positions[612] = Vec3( 0.762500, 0.905537, 3.044623);
positions[613] = Vec3( 0.755234, 0.859598, 3.133149);
positions[614] = Vec3( 0.798218, 0.997995, 3.057883);
positions[615] = Vec3( 0.680676, -0.494351, -0.010774);
positions[616] = Vec3( 0.580810, -0.498996, -0.008490);
positions[617] = Vec3( 0.716766, -0.507277, 0.081586);
positions[618] = Vec3( 2.917724, -1.534050, 0.840683);
positions[619] = Vec3( 2.859376, -1.575657, 0.770938);
positions[620] = Vec3( 2.995085, -1.488532, 0.796600);
positions[621] = Vec3(-0.233446, 3.889346, -3.039901);
positions[622] = Vec3(-0.139397, 3.857065, -3.050517);
positions[623] = Vec3(-0.280854, 3.883369, -3.127746);
positions[624] = Vec3(-0.208351, -3.847758, 5.537400);
positions[625] = Vec3(-0.282760, -3.805549, 5.485615);
positions[626] = Vec3(-0.136955, -3.878215, 5.474352);
positions[627] = Vec3(-0.619020, 4.568055, 1.317877);
positions[628] = Vec3(-0.696158, 4.517993, 1.278588);
positions[629] = Vec3(-0.568982, 4.614752, 1.244969);
positions[630] = Vec3( 0.635530, -6.590330, 0.788232);
positions[631] = Vec3( 0.560694, -6.637403, 0.834963);
positions[632] = Vec3( 0.644434, -6.497596, 0.824578);
positions[633] = Vec3( 2.553882, -4.117397, 1.927050);
positions[634] = Vec3( 2.608650, -4.069960, 1.858129);
positions[635] = Vec3( 2.465884, -4.071036, 1.937394);
positions[636] = Vec3( 3.484672, -1.021402, 2.940269);
positions[637] = Vec3( 3.561743, -1.076715, 2.908637);
positions[638] = Vec3( 3.436151, -0.983648, 2.861401);
positions[639] = Vec3( 3.762842, 5.220653, -2.951541);
positions[640] = Vec3( 3.740154, 5.209199, -3.048257);
positions[641] = Vec3( 3.723848, 5.306447, -2.918091);
positions[642] = Vec3( 3.133044, -5.642421, 6.152207);
positions[643] = Vec3( 3.174367, -5.580984, 6.084992);
positions[644] = Vec3( 3.076230, -5.709937, 6.105155);
positions[645] = Vec3( 3.772060, -2.877202, -3.528411);
positions[646] = Vec3( 3.768253, -2.940948, -3.451457);
positions[647] = Vec3( 3.782581, -2.928435, -3.613643);
positions[648] = Vec3( 2.745035, -0.324758, 5.134892);
positions[649] = Vec3( 2.731644, -0.265161, 5.055716);
positions[650] = Vec3( 2.699494, -0.412317, 5.118785);
positions[651] = Vec3( 2.444359, -1.074741, 6.063489);
positions[652] = Vec3( 2.398170, -1.038985, 5.982322);
positions[653] = Vec3( 2.511455, -1.007991, 6.095778);
positions[654] = Vec3( 2.959576, 4.521951, 3.337656);
positions[655] = Vec3( 2.982129, 4.426311, 3.319099);
positions[656] = Vec3( 2.908459, 4.528114, 3.423383);
positions[657] = Vec3( 2.993066, 5.855587, -1.657345);
positions[658] = Vec3( 3.086607, 5.852511, -1.622122);
positions[659] = Vec3( 2.961576, 5.762620, -1.676463);
positions[660] = Vec3( 3.389136, -5.310446, 0.288482);
positions[661] = Vec3( 3.378210, -5.390623, 0.347239);
positions[662] = Vec3( 3.312596, -5.305464, 0.224320);
positions[663] = Vec3( 2.274245, -2.011967, 2.038568);
positions[664] = Vec3( 2.325660, -2.092979, 2.066735);
positions[665] = Vec3( 2.290146, -1.937997, 2.103956);
positions[666] = Vec3( 3.001960, 0.759504, -1.515579);
positions[667] = Vec3( 3.091814, 0.786307, -1.480825);
positions[668] = Vec3( 3.005490, 0.664834, -1.547599);
positions[669] = Vec3(-0.120465, -1.115537, 4.672497);
positions[670] = Vec3(-0.059890, -1.082273, 4.744775);
positions[671] = Vec3(-0.068910, -1.174469, 4.610296);
positions[672] = Vec3( 0.683131, 0.865169, 1.342020);
positions[673] = Vec3( 0.661765, 0.875725, 1.439139);
positions[674] = Vec3( 0.639954, 0.781943, 1.307248);
positions[675] = Vec3( 2.355412, -0.255783, 4.121532);
positions[676] = Vec3( 2.353241, -0.286631, 4.216631);
positions[677] = Vec3( 2.342253, -0.334112, 4.060775);
positions[678] = Vec3( 2.486531, -6.378289, -2.191181);
positions[679] = Vec3( 2.553668, -6.436466, -2.237095);
positions[680] = Vec3( 2.523013, -6.285565, -2.182730);
positions[681] = Vec3( 2.706761, 3.327061, -0.579890);
positions[682] = Vec3( 2.615320, 3.314857, -0.618486);
positions[683] = Vec3( 2.748455, 3.409416, -0.618350);
positions[684] = Vec3( 3.648367, -0.672987, 3.539301);
positions[685] = Vec3( 3.697839, -0.723914, 3.468881);
positions[686] = Vec3( 3.667555, -0.712885, 3.628967);
positions[687] = Vec3( 3.259913, -0.102683, 0.435441);
positions[688] = Vec3( 3.313813, -0.088561, 0.518479);
positions[689] = Vec3( 3.269032, -0.022923, 0.375816);
positions[690] = Vec3(-0.280062, 3.348389, -1.678449);
positions[691] = Vec3(-0.341296, 3.376943, -1.752172);
positions[692] = Vec3(-0.185136, 3.361891, -1.706852);
positions[693] = Vec3( 2.967073, 4.255103, 3.205591);
positions[694] = Vec3( 3.057283, 4.249000, 3.162873);
positions[695] = Vec3( 2.941843, 4.165896, 3.243081);
positions[696] = Vec3( 3.631743, -2.037659, 3.445376);
positions[697] = Vec3( 3.699129, -2.044011, 3.518988);
positions[698] = Vec3( 3.539794, -2.047586, 3.483411);
positions[699] = Vec3( 3.706339, -2.402529, -0.306265);
positions[700] = Vec3( 3.712233, -2.465019, -0.384112);
positions[701] = Vec3( 3.710057, -2.454880, -0.221144);
positions[702] = Vec3( 2.649278, -0.287780, 2.362003);
positions[703] = Vec3( 2.550827, -0.304378, 2.367645);
positions[704] = Vec3( 2.681822, -0.311145, 2.270378);
positions[705] = Vec3( 3.509215, 0.322535, 3.976690);
positions[706] = Vec3( 3.439833, 0.391081, 3.998770);
positions[707] = Vec3( 3.464895, 0.241160, 3.939088);
positions[708] = Vec3( 2.817092, 5.585205, 2.554250);
positions[709] = Vec3( 2.764762, 5.508632, 2.591643);
positions[710] = Vec3( 2.762854, 5.631593, 2.484204);
positions[711] = Vec3(-0.291111, -1.095519, -1.101113);
positions[712] = Vec3(-0.363200, -1.108133, -1.169259);
positions[713] = Vec3(-0.244304, -1.008736, -1.117780);
positions[714] = Vec3( 3.615203, -2.543014, 3.111611);
positions[715] = Vec3( 3.595678, -2.497174, 3.024907);
positions[716] = Vec3( 3.591638, -2.482274, 3.187474);
positions[717] = Vec3( 3.328319, -1.549908, -1.625635);
positions[718] = Vec3( 3.269650, -1.548737, -1.544662);
positions[719] = Vec3( 3.281531, -1.597652, -1.700008);
positions[720] = Vec3( 3.320910, -3.150283, -4.376570);
positions[721] = Vec3( 3.307994, -3.247465, -4.396292);
positions[722] = Vec3( 3.250383, -3.097098, -4.423444);
positions[723] = Vec3( 2.583033, 1.769150, 0.771652);
positions[724] = Vec3( 2.619915, 1.808037, 0.687228);
positions[725] = Vec3( 2.584022, 1.669339, 0.765592);
positions[726] = Vec3(-0.264287, 2.756493, 3.906833);
positions[727] = Vec3(-0.332638, 2.778232, 3.976516);
positions[728] = Vec3(-0.184727, 2.714218, 3.950227);
positions[729] = Vec3( 2.294992, 1.153907, 1.071476);
positions[730] = Vec3( 2.278118, 1.158303, 0.973008);
positions[731] = Vec3( 2.344124, 1.236002, 1.100572);
positions[732] = Vec3( 2.715862, 4.143659, 0.240097);
positions[733] = Vec3( 2.639343, 4.202852, 0.265415);
positions[734] = Vec3( 2.754473, 4.102049, 0.322424);
positions[735] = Vec3(-0.174226, -1.974745, -1.969349);
positions[736] = Vec3(-0.222966, -2.002768, -2.052048);
positions[737] = Vec3(-0.239108, -1.935701, -1.904035);
positions[738] = Vec3( 3.047973, 3.330222, 7.112626);
positions[739] = Vec3( 3.026698, 3.233659, 7.127556);
positions[740] = Vec3( 3.136620, 3.351558, 7.153693);
positions[741] = Vec3(-0.393699, 0.586929, -1.711976);
positions[742] = Vec3(-0.482331, 0.602533, -1.755574);
positions[743] = Vec3(-0.360457, 0.672562, -1.672453);
positions[744] = Vec3( 2.966132, 0.314215, -2.297786);
positions[745] = Vec3( 2.941995, 0.252976, -2.373066);
positions[746] = Vec3( 2.884182, 0.361936, -2.266054);
positions[747] = Vec3( 2.914953, -2.370183, 4.211934);
positions[748] = Vec3( 2.960882, -2.458920, 4.215957);
positions[749] = Vec3( 2.845417, -2.371869, 4.140087);
positions[750] = Vec3( 3.716526, -2.209304, 2.568557);
positions[751] = Vec3( 3.732236, -2.305034, 2.592827);
positions[752] = Vec3( 3.747116, -2.193258, 2.474713);
positions[753] = Vec3( 0.415175, -0.581037, 1.625340);
positions[754] = Vec3( 0.493524, -0.596867, 1.565249);
positions[755] = Vec3( 0.377443, -0.668852, 1.654745);
positions[756] = Vec3( 0.242333, 5.858204, 3.893422);
positions[757] = Vec3( 0.322938, 5.833524, 3.947216);
positions[758] = Vec3( 0.160212, 5.847009, 3.949376);
positions[759] = Vec3( 2.390089, 2.669211, -1.980020);
positions[760] = Vec3( 2.427633, 2.636702, -2.066816);
positions[761] = Vec3( 2.425015, 2.760934, -1.960865);
positions[762] = Vec3( 3.014492, 2.203931, 2.864888);
positions[763] = Vec3( 2.936511, 2.259757, 2.836558);
positions[764] = Vec3( 3.071399, 2.256009, 2.928523);
positions[765] = Vec3( 0.323165, 3.040241, 1.951140);
positions[766] = Vec3( 0.224944, 3.058990, 1.952225);
positions[767] = Vec3( 0.338268, 2.942394, 1.937073);
positions[768] = Vec3(-0.577132, 1.872481, 0.949319);
positions[769] = Vec3(-0.533177, 1.956298, 0.981610);
positions[770] = Vec3(-0.525663, 1.835529, 0.871953);
positions[771] = Vec3( 2.833438, -1.434108, -0.914860);
positions[772] = Vec3( 2.888548, -1.444679, -0.832088);
positions[773] = Vec3( 2.887696, -1.460457, -0.994620);
positions[774] = Vec3( 3.039821, -0.976736, 6.205984);
positions[775] = Vec3( 3.008810, -0.906978, 6.270577);
positions[776] = Vec3( 3.072872, -0.932584, 6.122568);
positions[777] = Vec3( 3.468300, -2.105718, 2.628234);
positions[778] = Vec3( 3.439601, -2.139235, 2.717973);
positions[779] = Vec3( 3.558621, -2.142560, 2.606216);
positions[780] = Vec3( 3.684917, -0.254671, 2.254516);
positions[781] = Vec3( 3.693656, -0.211944, 2.164527);
positions[782] = Vec3( 3.588151, -0.262141, 2.278612);
positions[783] = Vec3( 2.368002, 4.299916, -1.373205);
positions[784] = Vec3( 2.436907, 4.278560, -1.303952);
positions[785] = Vec3( 2.336716, 4.215279, -1.416306);
positions[786] = Vec3(-0.699326, -3.461226, 2.295128);
positions[787] = Vec3(-0.710326, -3.525025, 2.218913);
positions[788] = Vec3(-0.733704, -3.371189, 2.268454);
positions[789] = Vec3(-0.458158, 8.191768, 0.025092);
positions[790] = Vec3(-0.535593, 8.253676, 0.038177);
positions[791] = Vec3(-0.462373, 8.118336, 0.092841);
positions[792] = Vec3( 2.547013, 2.300044, -0.233523);
positions[793] = Vec3( 2.542738, 2.251924, -0.145966);
positions[794] = Vec3( 2.506142, 2.243127, -0.304867);
positions[795] = Vec3( 2.372049, 0.060251, -3.503649);
positions[796] = Vec3( 2.309098, 0.010835, -3.443689);
positions[797] = Vec3( 2.465942, 0.032096, -3.483864);
positions[798] = Vec3( 0.323555, -0.668606, -2.800924);
positions[799] = Vec3( 0.402851, -0.612076, -2.778200);
positions[800] = Vec3( 0.352084, -0.764044, -2.809734);
positions[801] = Vec3( 3.334616, 1.721019, 8.886789);
positions[802] = Vec3( 3.304579, 1.731748, 8.981566);
positions[803] = Vec3( 3.307335, 1.630873, 8.853181);
positions[804] = Vec3( 2.366604, 3.566070, 3.138453);
positions[805] = Vec3( 2.343743, 3.597942, 3.046466);
positions[806] = Vec3( 2.379377, 3.644788, 3.198788);
positions[807] = Vec3( 0.196988, -4.566388, 4.848518);
positions[808] = Vec3( 0.148553, -4.557274, 4.761507);
positions[809] = Vec3( 0.130979, -4.565757, 4.923635);
positions[810] = Vec3( 3.349403, 0.092204, 3.037136);
positions[811] = Vec3( 3.312214, 0.023625, 3.099697);
positions[812] = Vec3( 3.448522, 0.097944, 3.049071);
positions[813] = Vec3( 2.309733, -6.738473, 2.018939);
positions[814] = Vec3( 2.250135, -6.663433, 1.990356);
positions[815] = Vec3( 2.288891, -6.820015, 1.964935);
positions[816] = Vec3( 3.137597, 3.282022, -3.490887);
positions[817] = Vec3( 3.071044, 3.208752, -3.505108);
positions[818] = Vec3( 3.227583, 3.242286, -3.472898);
positions[819] = Vec3( 0.563585, 0.642427, -0.780897);
positions[820] = Vec3( 0.533445, 0.601977, -0.694553);
positions[821] = Vec3( 0.483808, 0.671425, -0.833763);
positions[822] = Vec3( 3.609444, -5.831914, -2.958009);
positions[823] = Vec3( 3.661093, -5.878615, -3.029783);
positions[824] = Vec3( 3.630415, -5.734159, -2.960086);
positions[825] = Vec3(-0.678745, 3.620307, -1.127529);
positions[826] = Vec3(-0.658455, 3.717696, -1.117346);
positions[827] = Vec3(-0.674486, 3.595309, -1.224261);
positions[828] = Vec3( 2.671475, 1.301782, -0.159480);
positions[829] = Vec3( 2.648253, 1.379810, -0.217552);
positions[830] = Vec3( 2.637707, 1.217631, -0.201649);
positions[831] = Vec3( 3.207226, -5.031230, -1.180231);
positions[832] = Vec3( 3.151180, -5.077289, -1.111402);
positions[833] = Vec3( 3.238540, -4.943309, -1.144324);
positions[834] = Vec3( 2.645076, -0.528506, 5.640103);
positions[835] = Vec3( 2.714750, -0.465715, 5.605422);
positions[836] = Vec3( 2.634885, -0.605245, 5.576800);
positions[837] = Vec3( 2.889189, 0.965149, 5.796705);
positions[838] = Vec3( 2.828895, 0.894433, 5.833636);
positions[839] = Vec3( 2.844802, 1.009451, 5.718814);
positions[840] = Vec3( 3.711559, -4.135044, 1.684152);
positions[841] = Vec3( 3.730833, -4.231658, 1.701308);
positions[842] = Vec3( 3.617995, -4.114157, 1.712606);
positions[843] = Vec3( 2.491295, -5.434512, 3.781500);
positions[844] = Vec3( 2.585423, -5.408173, 3.802623);
positions[845] = Vec3( 2.485320, -5.534088, 3.774498);
positions[846] = Vec3( 3.266099, 0.379577, 3.738288);
positions[847] = Vec3( 3.166151, 0.381614, 3.735805);
positions[848] = Vec3( 3.297995, 0.286504, 3.720396);
positions[849] = Vec3( 3.371176, -2.787672, 0.812740);
positions[850] = Vec3( 3.385259, -2.811354, 0.716611);
positions[851] = Vec3( 3.307966, -2.710447, 0.819128);
positions[852] = Vec3( 3.410889, -0.832711, -2.284455);
positions[853] = Vec3( 3.383318, -0.866157, -2.194337);
positions[854] = Vec3( 3.508677, -0.849001, -2.297571);
positions[855] = Vec3( 3.652077, -1.435559, -5.501856);
positions[856] = Vec3( 3.565618, -1.391700, -5.477337);
positions[857] = Vec3( 3.635931, -1.532198, -5.521863);
positions[858] = Vec3( 2.930415, 3.088887, 2.455184);
positions[859] = Vec3( 2.899953, 3.111836, 2.547625);
positions[860] = Vec3( 2.934824, 2.989478, 2.445258);
positions[861] = Vec3( 2.675796, -0.364050, 2.068402);
positions[862] = Vec3( 2.632458, -0.286274, 2.022874);
positions[863] = Vec3( 2.625737, -0.447746, 2.046286);
positions[864] = Vec3( 3.345653, 0.758773, 5.926481);
positions[865] = Vec3( 3.290578, 0.740435, 5.845053);
positions[866] = Vec3( 3.286227, 0.762204, 6.006835);
positions[867] = Vec3( 3.702425, 0.526961, 1.652046);
positions[868] = Vec3( 3.739286, 0.590091, 1.720279);
positions[869] = Vec3( 3.713823, 0.432911, 1.684055);
positions[870] = Vec3( 3.591287, 0.305830, -1.604704);
positions[871] = Vec3( 3.496244, 0.334437, -1.616890);
positions[872] = Vec3( 3.629674, 0.279192, -1.693117);
positions[873] = Vec3( 3.194190, -2.498706, -2.519364);
positions[874] = Vec3( 3.136703, -2.579601, -2.531663);
positions[875] = Vec3( 3.281053, -2.525562, -2.477728);
positions[876] = Vec3( 3.733965, 0.153157, 4.815445);
positions[877] = Vec3( 3.668302, 0.162458, 4.740600);
positions[878] = Vec3( 3.789750, 0.235942, 4.821326);
positions[879] = Vec3( 2.368074, -1.184309, 1.135001);
positions[880] = Vec3( 2.320190, -1.162736, 1.049903);
positions[881] = Vec3( 2.460912, -1.215061, 1.114133);
positions[882] = Vec3( 2.911423, -6.635674, -0.301101);
positions[883] = Vec3( 2.868203, -6.708336, -0.247694);
positions[884] = Vec3( 2.855003, -6.553213, -0.296977);
positions[885] = Vec3(-0.116015, 1.225084, -7.310834);
positions[886] = Vec3(-0.132525, 1.228575, -7.212268);
positions[887] = Vec3(-0.040174, 1.285967, -7.334103);
positions[888] = Vec3( 2.627563, 1.045290, 2.246684);
positions[889] = Vec3( 2.705739, 1.103297, 2.269568);
positions[890] = Vec3( 2.637963, 0.956296, 2.291089);
positions[891] = Vec3( 2.756519, 0.751061, -0.434944);
positions[892] = Vec3( 2.754053, 0.651676, -0.445746);
positions[893] = Vec3( 2.763769, 0.773865, -0.337849);
positions[894] = Vec3( 3.731464, 2.951593, 4.280964);
positions[895] = Vec3( 3.734304, 3.036685, 4.228511);
positions[896] = Vec3( 3.721193, 2.874225, 4.218445);
positions[897] = Vec3( 2.617057, 1.442059, -0.901155);
positions[898] = Vec3( 2.530722, 1.491826, -0.892818);
positions[899] = Vec3( 2.607198, 1.351188, -0.860593);
positions[900] = Vec3( 0.406702, -2.735119, 0.092225);
positions[901] = Vec3( 0.402591, -2.669190, 0.017149);
positions[902] = Vec3( 0.383278, -2.826112, 0.057998);
positions[903] = Vec3( 3.354762, -1.246425, 3.101514);
positions[904] = Vec3( 3.388721, -1.170200, 3.046409);
positions[905] = Vec3( 3.273259, -1.217533, 3.151739);
positions[906] = Vec3( 3.279952, 2.489570, -2.005630);
positions[907] = Vec3( 3.329451, 2.575044, -1.990010);
positions[908] = Vec3( 3.272828, 2.472664, -2.103933);
positions[909] = Vec3( 2.860709, -0.346879, -0.410117);
positions[910] = Vec3( 2.944291, -0.316620, -0.364309);
positions[911] = Vec3( 2.857033, -0.307703, -0.502050);
positions[912] = Vec3( 2.393225, -0.525007, 1.422487);
positions[913] = Vec3( 2.377810, -0.531048, 1.323867);
positions[914] = Vec3( 2.411934, -0.616224, 1.458948);
positions[915] = Vec3( 3.444261, -1.032071, 2.380373);
positions[916] = Vec3( 3.433960, -1.124856, 2.344528);
positions[917] = Vec3( 3.484313, -0.973403, 2.309989);
positions[918] = Vec3( 3.077241, -0.888721, -0.055938);
positions[919] = Vec3( 3.010108, -0.926187, -0.119887);
positions[920] = Vec3( 3.083109, -0.789628, -0.068033);
positions[921] = Vec3( 3.129255, 2.070554, 2.657921);
positions[922] = Vec3( 3.092017, 2.133510, 2.726112);
positions[923] = Vec3( 3.187820, 2.003279, 2.703134);
positions[924] = Vec3( 3.363559, 0.279124, 0.791844);
positions[925] = Vec3( 3.369946, 0.213807, 0.867296);
positions[926] = Vec3( 3.420687, 0.248007, 0.715896);
positions[927] = Vec3( 2.995047, -4.376949, -2.064391);
positions[928] = Vec3( 3.026113, -4.365827, -2.158791);
positions[929] = Vec3( 2.994226, -4.287918, -2.018863);
positions[930] = Vec3( 0.692594, 3.189527, -3.855512);
positions[931] = Vec3( 0.603685, 3.228311, -3.879820);
positions[932] = Vec3( 0.753379, 3.262521, -3.824253);
positions[933] = Vec3( 2.444212, -1.569678, -1.014264);
positions[934] = Vec3( 2.412781, -1.486737, -1.060449);
positions[935] = Vec3( 2.472841, -1.636986, -1.082454);
positions[936] = Vec3( 3.616946, 0.438895, -2.963453);
positions[937] = Vec3( 3.622035, 0.514915, -2.898683);
positions[938] = Vec3( 3.650363, 0.468929, -3.052790);
positions[939] = Vec3( 2.303248, 3.014900, 5.852802);
positions[940] = Vec3( 2.219381, 2.966372, 5.877527);
positions[941] = Vec3( 2.327173, 2.993934, 5.757997);
positions[942] = Vec3(-0.390806, 6.292520, 1.389308);
positions[943] = Vec3(-0.357274, 6.321060, 1.299525);
positions[944] = Vec3(-0.490673, 6.297479, 1.390711);
positions[945] = Vec3( 2.288403, 1.641080, 1.620128);
positions[946] = Vec3( 2.299878, 1.577433, 1.543856);
positions[947] = Vec3( 2.373416, 1.645946, 1.672559);
positions[948] = Vec3(-0.729092, 3.182282, -1.207870);
positions[949] = Vec3(-0.668056, 3.188837, -1.286812);
positions[950] = Vec3(-0.822297, 3.164119, -1.239220);
positions[951] = Vec3(-0.109054, 5.822135, 4.713540);
positions[952] = Vec3(-0.108044, 5.728808, 4.677638);
positions[953] = Vec3(-0.159553, 5.881431, 4.650819);
positions[954] = Vec3( 0.417370, 1.976387, -0.389305);
positions[955] = Vec3( 0.436483, 2.070945, -0.415637);
positions[956] = Vec3( 0.318932, 1.964700, -0.376139);
positions[957] = Vec3( 0.254203, -3.946639, 2.182278);
positions[958] = Vec3( 0.173707, -4.003089, 2.164009);
positions[959] = Vec3( 0.257073, -3.870663, 2.117320);
positions[960] = Vec3(-0.441793, 1.189060, -2.837110);
positions[961] = Vec3(-0.358767, 1.140944, -2.808979);
positions[962] = Vec3(-0.521726, 1.132894, -2.815752);
positions[963] = Vec3(-0.195998, 0.270336, -1.384474);
positions[964] = Vec3(-0.229102, 0.349637, -1.435616);
positions[965] = Vec3(-0.159310, 0.202539, -1.448172);
refCharges[ 0] = -3.7499017125053012e-02;
refCharges[ 1] = -8.7221183536224395e-03;
refCharges[ 2] = -2.1558052255085839e-02;
refCharges[ 3] = -1.3084815465192520e-02;
refCharges[ 4] = -3.2624629921696638e-02;
refCharges[ 5] = -2.1921804824808530e-02;
refCharges[ 6] = -2.1612291880366910e-02;
refCharges[ 7] = -3.8399519523242679e-03;
refCharges[ 8] = -3.7583178364320957e-02;
refCharges[ 9] = -1.3026269198110580e-02;
refCharges[ 10] = -2.1370760767039379e-02;
refCharges[ 11] = -4.9334447410992544e-03;
refCharges[ 12] = -2.3764413607488051e-02;
refCharges[ 13] = -3.5541259910837051e-03;
refCharges[ 14] = -2.0403375287844559e-02;
refCharges[ 15] = -3.6621033760161829e-03;
refCharges[ 16] = -2.6128649964438311e-02;
refCharges[ 17] = -3.4586115198422182e-03;
refCharges[ 18] = -1.2759096007071331e-02;
refCharges[ 19] = -2.5651438019624329e-03;
refCharges[ 20] = -1.7232443159828480e-02;
refCharges[ 21] = -6.6513926299824290e-03;
refCharges[ 22] = -3.4816759620043690e-03;
refCharges[ 23] = -1.1589281492165680e-02;
refCharges[ 24] = -5.5618338035569341e-03;
refCharges[ 25] = -5.8288915932467071e-03;
refCharges[ 26] = -1.7620184084467031e-03;
refCharges[ 27] = -1.8594666497272871e-03;
refCharges[ 28] = +1.1896735880129270e-04;
refCharges[ 29] = -3.9361895923986194e-03;
refCharges[ 30] = -2.5800549436554108e-03;
refCharges[ 31] = -2.3835739987747850e-03;
refCharges[ 32] = -3.4967585781609388e-03;
refCharges[ 33] = +4.7412040361380723e-03;
refCharges[ 34] = -1.6761114467671969e-03;
refCharges[ 35] = -1.8669113807494989e-03;
refCharges[ 36] = -5.7981160810977148e-04;
refCharges[ 37] = -8.2898817378893291e-04;
refCharges[ 38] = +7.0761739609553030e-03;
refCharges[ 39] = -1.9935334570884630e-03;
refCharges[ 40] = -2.3543719857765221e-02;
refCharges[ 41] = -1.3248875964774731e-02;
refCharges[ 42] = -2.2098944678214431e-03;
refCharges[ 43] = -1.2298258631497061e-02;
refCharges[ 44] = +3.4135125886801130e-03;
refCharges[ 45] = -1.0731167766544460e-02;
refCharges[ 46] = -2.4945834800850172e-03;
refCharges[ 47] = -8.3816053592841440e-04;
refCharges[ 48] = -5.3866640954979370e-03;
refCharges[ 49] = -2.8964774752105161e-03;
refCharges[ 50] = -2.5133103887756509e-03;
refCharges[ 51] = -2.4707101350449961e-03;
refCharges[ 52] = +7.5774563590465093e-03;
refCharges[ 53] = +2.3375745338813401e-02;
refCharges[ 54] = -8.6446524625826673e-04;
refCharges[ 55] = -1.6437290734041049e-04;
refCharges[ 56] = -1.3242290280428320e-02;
refCharges[ 57] = -2.3566206942501361e-02;
refCharges[ 58] = +4.2681955293865821e-03;
refCharges[ 59] = -2.2860332028030832e-03;
refCharges[ 60] = -3.1740062294384329e-02;
refCharges[ 61] = -1.0357457953543399e-02;
refCharges[ 62] = -3.4130862541603300e-03;
refCharges[ 63] = -1.2231434361707051e-02;
refCharges[ 64] = +1.3997438048692990e-03;
refCharges[ 65] = -1.2263679680227010e-02;
refCharges[ 66] = -2.1886135282875481e-03;
refCharges[ 67] = -3.5440522757362132e-03;
refCharges[ 68] = +3.5627636821225742e-03;
refCharges[ 69] = +5.1633832216429042e-03;
refCharges[ 70] = -1.2859519512336699e-04;
refCharges[ 71] = -1.9058632361095720e-03;
refCharges[ 72] = +1.0573023545073210e-02;
refCharges[ 73] = -1.2253742193179861e-03;
refCharges[ 74] = -1.3809952696691541e-03;
refCharges[ 75] = -1.5341869515697020e-03;
refCharges[ 76] = +7.1585659825117176e-04;
refCharges[ 77] = -3.8768810194521300e-03;
refCharges[ 78] = +6.9501407011860368e-03;
refCharges[ 79] = -1.7242615737758391e-03;
refCharges[ 80] = -2.3925532149081458e-02;
refCharges[ 81] = +7.2723090308843630e-03;
refCharges[ 82] = -2.0462530048019878e-03;
refCharges[ 83] = +6.6757471812437276e-03;
refCharges[ 84] = -2.3581432042933771e-02;
refCharges[ 85] = +1.3490521149983691e-02;
refCharges[ 86] = -1.3053262555938641e-03;
refCharges[ 87] = +1.5444767888608629e-02;
refCharges[ 88] = +6.6908260264036332e-03;
refCharges[ 89] = +1.4339687704711900e-02;
refCharges[ 90] = -3.8588032366180310e-04;
refCharges[ 91] = +1.7134778545750851e-02;
refCharges[ 92] = +6.2730241228376908e-03;
refCharges[ 93] = +2.6568792517389351e-02;
refCharges[ 94] = -5.1565077803794567e-05;
refCharges[ 95] = +1.6726389983062730e-02;
refCharges[ 96] = -1.9770471848499751e-04;
refCharges[ 97] = +8.7255366559639506e-03;
refCharges[ 98] = +6.9358989710860009e-03;
refCharges[ 99] = +1.7630254087606521e-02;
refCharges[100] = -5.0455081528717312e-02;
refCharges[101] = -2.5042963407476210e-02;
refCharges[102] = -1.7444314781858521e-02;
refCharges[103] = +1.9873521393648320e-02;
refCharges[104] = -4.2240107420690433e-02;
refCharges[105] = -2.5096298229849521e-02;
refCharges[106] = -2.5119073297938100e-02;
refCharges[107] = +4.6267454915552210e-02;
refCharges[108] = -4.1975631372433583e-02;
refCharges[109] = -2.5093070037377339e-02;
refCharges[110] = -2.5821331905895920e-02;
refCharges[111] = +4.6642027456686518e-02;
refCharges[112] = -4.2101841924201223e-02;
refCharges[113] = -2.5100125187860409e-02;
refCharges[114] = -2.2913645003797691e-02;
refCharges[115] = +4.8036428895199497e-02;
refCharges[116] = -4.2357633714718783e-02;
refCharges[117] = -1.7053802926315920e-02;
refCharges[118] = +6.6124220368523508e-03;
refCharges[119] = +4.2778132395273137e-02;
refCharges[120] = -3.4115868902060420e-02;
refCharges[121] = -2.5315935417211270e-02;
refCharges[122] = +4.0900229050443257e-02;
refCharges[123] = +5.0728360965071866e-03;
refCharges[124] = -2.5879005117041672e-02;
refCharges[125] = -2.5410963530005139e-02;
refCharges[126] = +3.3151999500710683e-02;
refCharges[127] = +3.5433594242325443e-02;
refCharges[128] = -2.5855948808607431e-02;
refCharges[129] = -2.5619250443058721e-02;
refCharges[130] = +3.4351239980264653e-02;
refCharges[131] = +3.6720765584744922e-02;
refCharges[132] = -2.5937095378312101e-02;
refCharges[133] = -2.5472420285465310e-02;
refCharges[134] = +3.6279696021088263e-02;
refCharges[135] = +3.6834644011608339e-02;
refCharges[136] = -2.6081759127337151e-02;
refCharges[137] = -1.7291091362336811e-02;
refCharges[138] = +6.4012971043744579e-02;
refCharges[139] = +3.0930555104196910e-02;
refCharges[140] = -3.3786366351913871e-02;
refCharges[141] = -2.5220679818635350e-02;
refCharges[142] = +4.1178375054304092e-02;
refCharges[143] = +3.5243896725811602e-03;
refCharges[144] = -2.5634714056628021e-02;
refCharges[145] = -2.5492329116884919e-02;
refCharges[146] = +3.5784221856079310e-02;
refCharges[147] = +3.3427051697688642e-02;
refCharges[148] = -2.5601542684902959e-02;
refCharges[149] = -2.5599594741689598e-02;
refCharges[150] = +3.6013038324809662e-02;
refCharges[151] = +3.6248805902797769e-02;
refCharges[152] = -2.5679601929462940e-02;
refCharges[153] = -2.5519825063262221e-02;
refCharges[154] = +3.7947261602409091e-02;
refCharges[155] = +3.6942322685648669e-02;
refCharges[156] = -2.5856442752026740e-02;
refCharges[157] = -1.7241413289559679e-02;
refCharges[158] = +6.5334517580538515e-02;
refCharges[159] = +2.9768575402207322e-02;
refCharges[160] = -3.3798412653506818e-02;
refCharges[161] = -2.5189594982922999e-02;
refCharges[162] = +4.0980686486184997e-02;
refCharges[163] = +9.6633219222573251e-03;
refCharges[164] = -2.5706059959092191e-02;
refCharges[165] = -2.5323146663132429e-02;
refCharges[166] = +3.6098546418277047e-02;
refCharges[167] = +3.6617344664340072e-02;
refCharges[168] = -2.5646946352001789e-02;
refCharges[169] = -2.5298516790796161e-02;
refCharges[170] = +3.5621928882280940e-02;
refCharges[171] = +3.7711343583140607e-02;
refCharges[172] = -2.5712133524380631e-02;
refCharges[173] = -2.5273588085519379e-02;
refCharges[174] = +3.7632233844094073e-02;
refCharges[175] = +3.9621661663901089e-02;
refCharges[176] = -2.5860301417634950e-02;
refCharges[177] = -1.7177581290792179e-02;
refCharges[178] = +6.5733736075615029e-02;
refCharges[179] = +3.2227354073899317e-02;
refCharges[180] = -3.4369476063724050e-02;
refCharges[181] = -8.9229552519534891e-03;
refCharges[182] = +3.2022363481488923e-02;
refCharges[183] = +6.6740571039338573e-02;
refCharges[184] = -2.6100941655793890e-02;
refCharges[185] = -8.9673068295257220e-03;
refCharges[186] = +2.2960682916255141e-02;
refCharges[187] = +9.5087421035470160e-02;
refCharges[188] = -2.5866289954439490e-02;
refCharges[189] = -8.9764078322591995e-03;
refCharges[190] = +2.4019225847072449e-02;
refCharges[191] = +9.4674685950216803e-02;
refCharges[192] = -2.6049459191277179e-02;
refCharges[193] = -8.9649265171629546e-03;
refCharges[194] = +2.4598979839840440e-02;
refCharges[195] = +9.6162552909227261e-02;
refCharges[196] = -2.6240785178439370e-02;
refCharges[197] = -8.8341203337631081e-04;
refCharges[198] = +5.4760458796402317e-02;
refCharges[199] = +9.0054241811072883e-02;
refCharges[200] = -1.0149134249212929e-01;
refCharges[201] = +8.1469082043992974e-03;
refCharges[202] = -1.8197805140852990e-02;
refCharges[203] = +1.7385927960370401e-03;
refCharges[204] = -6.1896682065123713e-02;
refCharges[205] = +1.8677318292907329e-02;
refCharges[206] = -1.5992021497332981e-01;
refCharges[207] = +3.3065483743651203e-02;
refCharges[208] = -5.6306960188908288e-02;
refCharges[209] = +3.7565380579267079e-03;
refCharges[210] = -4.2174853965660217e-02;
refCharges[211] = -8.4549106880354614e-03;
refCharges[212] = -6.3472972701101846e-02;
refCharges[213] = +1.0682385626524229e-03;
refCharges[214] = -5.6504074809451063e-02;
refCharges[215] = +4.4948289040807561e-02;
refCharges[216] = -7.5256930330876368e-02;
refCharges[217] = +3.1734571332401068e-02;
refCharges[218] = -2.7724605039610131e-02;
refCharges[219] = +4.0531360558442510e-02;
refCharges[220] = -4.9579110401481240e-02;
refCharges[221] = -1.1382343528569580e-04;
refCharges[222] = +2.9553437058404419e-02;
refCharges[223] = -1.5369583531395540e-02;
refCharges[224] = -2.5159530886317321e-02;
refCharges[225] = -1.8856911673284401e-02;
refCharges[226] = +1.6953778471357730e-02;
refCharges[227] = +5.3396325488436938e-02;
refCharges[228] = -1.0136735809647831e-02;
refCharges[229] = -9.4109592198970641e-03;
refCharges[230] = -4.4827691330999078e-02;
refCharges[231] = +1.0632548907150990e-02;
refCharges[232] = -1.7541362962335601e-02;
refCharges[233] = -1.8041877166636321e-02;
refCharges[234] = +2.9385193341849119e-02;
refCharges[235] = +3.6335305067773167e-02;
refCharges[236] = -3.2026504632650173e-02;
refCharges[237] = +1.9066875995947950e-02;
refCharges[238] = +5.7694864986103163e-02;
refCharges[239] = +3.2162612897706402e-02;
refCharges[240] = -2.4085398656351221e-02;
refCharges[241] = +7.9511141598730111e-03;
refCharges[242] = -7.7404428992801838e-02;
refCharges[243] = -3.1620091994375710e-02;
refCharges[244] = -1.0901123711692509e-02;
refCharges[245] = -1.0520627185098160e-02;
refCharges[246] = +4.6572694176910220e-02;
refCharges[247] = +1.3721143246800880e-03;
refCharges[248] = -1.4998851756616881e-02;
refCharges[249] = -1.0861192978700029e-02;
refCharges[250] = +2.7031483678783282e-02;
refCharges[251] = -1.7095892567721500e-02;
refCharges[252] = -1.9002180724839259e-02;
refCharges[253] = -1.4645230648590350e-02;
refCharges[254] = +4.4732534398644920e-02;
refCharges[255] = +1.3381422278055071e-02;
refCharges[256] = -2.0919675566049310e-02;
refCharges[257] = +2.1555207339307061e-02;
refCharges[258] = -3.6283109608009893e-02;
refCharges[259] = +1.6012730025695511e-02;
refCharges[260] = -4.0588242747413378e-02;
refCharges[261] = -7.7667222564147204e-03;
refCharges[262] = +5.5918655481978358e-03;
refCharges[263] = +1.2863150452299479e-02;
refCharges[264] = -9.6056871922834269e-03;
refCharges[265] = -3.6113764246106030e-04;
refCharges[266] = -8.0724773986928469e-02;
refCharges[267] = +3.6691025611407489e-02;
refCharges[268] = -8.3108124581734149e-03;
refCharges[269] = -1.8197253773095900e-02;
refCharges[270] = +3.6504125520162120e-02;
refCharges[271] = +4.2968104326385440e-02;
refCharges[272] = -1.8285804807371280e-02;
refCharges[273] = -9.4006708873478444e-03;
refCharges[274] = +2.7210780545237439e-02;
refCharges[275] = +2.4092993166445510e-02;
refCharges[276] = -2.3991845397306259e-02;
refCharges[277] = +1.6440824213247478e-02;
refCharges[278] = +2.6289466963886541e-02;
refCharges[279] = +2.4755671932533849e-02;
refCharges[280] = -6.5564087394358789e-02;
refCharges[281] = +4.0737945130334699e-02;
refCharges[282] = +2.5934116429342052e-02;
refCharges[283] = +1.1866632793328370e-01;
refCharges[284] = -3.4246251031122631e-02;
refCharges[285] = +5.2222889410715227e-02;
refCharges[286] = -1.7058180758775771e-02;
refCharges[287] = +6.3936044935101438e-02;
refCharges[288] = -3.1295923177334921e-02;
refCharges[289] = +4.6264348668046060e-02;
refCharges[290] = +3.5252042016436468e-02;
refCharges[291] = +5.2870823861281890e-02;
refCharges[292] = -3.1182042720254880e-02;
refCharges[293] = +4.6862828424374947e-02;
refCharges[294] = +1.5248475499623740e-03;
refCharges[295] = +2.4542352529025459e-02;
refCharges[296] = -3.5232711966025100e-02;
refCharges[297] = +6.8505583787853222e-02;
refCharges[298] = +8.8037665717154157e-03;
refCharges[299] = +4.5624039170556192e-02;
refCharges[ 0] = -5.7975746417753904e-04;
refCharges[ 1] = +3.0455110381333562e-03;
refCharges[ 2] = -3.1872210706934950e-03;
refCharges[ 3] = -2.9931087895700421e-03;
refCharges[ 4] = -3.5951095964409760e-03;
refCharges[ 5] = -7.0940192766586032e-03;
refCharges[ 6] = -4.0095538328028934e-03;
refCharges[ 7] = -3.1594851477446781e-03;
refCharges[ 8] = -7.2227427670462476e-03;
refCharges[ 9] = -1.3428977971308609e-03;
refCharges[ 10] = -3.4638674247797901e-03;
refCharges[ 11] = -4.0434532645985746e-03;
refCharges[ 12] = +2.2076290659519900e-03;
refCharges[ 13] = +4.6610877914713220e-03;
refCharges[ 14] = -2.3719643905962639e-03;
refCharges[ 15] = -2.6757134576374780e-03;
refCharges[ 16] = -1.1426572131276189e-03;
refCharges[ 17] = -2.0847666293578788e-03;
refCharges[ 18] = -4.2104190001737317e-03;
refCharges[ 19] = -2.5733004823314449e-03;
refCharges[ 20] = +8.7293790250853899e-04;
refCharges[ 21] = +2.0144784854433041e-03;
refCharges[ 22] = -3.0010028559411869e-03;
refCharges[ 23] = -3.2097251078502388e-03;
refCharges[ 24] = +2.4246071822816521e-03;
refCharges[ 25] = +1.6111718607232060e-03;
refCharges[ 26] = -2.5128340259021891e-03;
refCharges[ 27] = -2.3124602976548670e-03;
refCharges[ 28] = +5.4886906969139580e-03;
refCharges[ 29] = +2.7089268908000921e-03;
refCharges[ 30] = -2.8438295591086912e-03;
refCharges[ 31] = -2.7372867434326941e-03;
refCharges[ 32] = +3.3464833909417529e-03;
refCharges[ 33] = +7.7341035780085091e-03;
refCharges[ 34] = -2.0420720167916972e-03;
refCharges[ 35] = -2.0184547020835660e-03;
refCharges[ 36] = +3.4961575044787519e-03;
refCharges[ 37] = -3.3888147629074399e-03;
refCharges[ 38] = -2.9671477093004229e-03;
refCharges[ 39] = -3.2727794523739308e-03;
refCharges[ 40] = -5.4642073067298113e-03;
refCharges[ 41] = -3.9365778892971708e-03;
refCharges[ 42] = -2.5370412881391279e-03;
refCharges[ 43] = -4.6857563887033500e-03;
refCharges[ 44] = +7.1323367072630471e-03;
refCharges[ 45] = -2.5654526216082820e-03;
refCharges[ 46] = -2.8874370602631548e-03;
refCharges[ 47] = -1.9725872304638750e-03;
refCharges[ 48] = +1.1244889701763270e-03;
refCharges[ 49] = +2.9147677066563731e-03;
refCharges[ 50] = -2.5920480394061550e-03;
refCharges[ 51] = -2.8557329348401711e-03;
refCharges[ 52] = +1.0124491284778849e-02;
refCharges[ 53] = +1.9254738994731419e-02;
refCharges[ 54] = -1.3050582107588251e-03;
refCharges[ 55] = -4.1068029343605802e-04;
refCharges[ 56] = -6.2864576522783716e-03;
refCharges[ 57] = -2.0008530808701949e-02;
refCharges[ 58] = -5.8275182695347741e-03;
refCharges[ 59] = -3.7403888225161432e-03;
refCharges[ 60] = -1.2320581716078640e-02;
refCharges[ 61] = -4.1257422419994786e-03;
refCharges[ 62] = -3.9074043734491871e-03;
refCharges[ 63] = -4.6331094651083198e-03;
refCharges[ 64] = +4.1903758676002786e-03;
refCharges[ 65] = -5.4565990228810394e-03;
refCharges[ 66] = -2.9491076667158139e-03;
refCharges[ 67] = -4.5791310375362746e-03;
refCharges[ 68] = +6.0482956101459880e-03;
refCharges[ 69] = +6.8015540385970930e-03;
refCharges[ 70] = -8.3049335883931695e-04;
refCharges[ 71] = -2.5469297745339429e-03;
refCharges[ 72] = +1.1242440554052510e-02;
refCharges[ 73] = +1.6829298780320591e-03;
refCharges[ 74] = -1.6325163655022640e-03;
refCharges[ 75] = -1.8829033634548591e-03;
refCharges[ 76] = +1.6486924869102001e-03;
refCharges[ 77] = -8.3249182215618979e-03;
refCharges[ 78] = -4.2918032894321140e-03;
refCharges[ 79] = -3.5295020514801300e-03;
refCharges[ 80] = -9.7736639424608491e-03;
refCharges[ 81] = -4.8750141664973528e-03;
refCharges[ 82] = -4.4506070294596392e-03;
refCharges[ 83] = -4.1590909476453726e-03;
refCharges[ 84] = -1.5314159650913151e-02;
refCharges[ 85] = -1.7454771382899470e-03;
refCharges[ 86] = -3.9241940000646408e-03;
refCharges[ 87] = -4.4086864982293564e-03;
refCharges[ 88] = +5.0044734054314399e-03;
refCharges[ 89] = -5.1769315731655492e-04;
refCharges[ 90] = -2.3390435445166491e-03;
refCharges[ 91] = -2.7590119963415618e-03;
refCharges[ 92] = +5.0184890719422214e-03;
refCharges[ 93] = +6.9350465763378744e-03;
refCharges[ 94] = -2.3292208219996341e-03;
refCharges[ 95] = -2.4767178777486362e-03;
refCharges[ 96] = -1.7980190205113930e-03;
refCharges[ 97] = -1.2169434129813479e-02;
refCharges[ 98] = -5.0795257224505860e-03;
refCharges[ 99] = -3.0259536513629272e-03;
refCharges[100] = -1.6647083816976969e-02;
refCharges[101] = -1.6554241172769119e-02;
refCharges[102] = +2.2333039341854322e-02;
refCharges[103] = +2.2562217657356179e-02;
refCharges[104] = -1.6676520439585261e-02;
refCharges[105] = -1.6652949403795251e-02;
refCharges[106] = +2.3010293177341420e-02;
refCharges[107] = +2.2425001112276272e-02;
refCharges[108] = -1.6683555521352509e-02;
refCharges[109] = -1.6594206859397189e-02;
refCharges[110] = +2.2413908997122090e-02;
refCharges[111] = +2.2692527125975200e-02;
refCharges[112] = -1.6525243155568189e-02;
refCharges[113] = -1.6461933086700398e-02;
refCharges[114] = +2.2677947058074230e-02;
refCharges[115] = +2.2505638392329889e-02;
refCharges[116] = -1.6572598648360179e-02;
refCharges[117] = -1.6589311389078730e-02;
refCharges[118] = +2.2567635670515940e-02;
refCharges[119] = +2.2486976385733971e-02;
refCharges[120] = -1.6558381327457291e-02;
refCharges[121] = -1.6527693786971592e-02;
refCharges[122] = +2.2497939346495761e-02;
refCharges[123] = +2.2543943597797100e-02;
refCharges[124] = -1.6515370396020818e-02;
refCharges[125] = -1.6486316566618819e-02;
refCharges[126] = +2.2359294069455790e-02;
refCharges[127] = +2.2327607902493711e-02;
refCharges[128] = -1.6565102693228709e-02;
refCharges[129] = -1.6483170860793241e-02;
refCharges[130] = +2.2931231147926650e-02;
refCharges[131] = +2.2571991109099840e-02;
refCharges[132] = -1.6463229989553661e-02;
refCharges[133] = -1.6414164011126890e-02;
refCharges[134] = +2.2529812817050490e-02;
refCharges[135] = +2.2538301458271081e-02;
refCharges[136] = -1.6499748644462561e-02;
refCharges[137] = -1.6688896293304500e-02;
refCharges[138] = +2.2439752384255461e-02;
refCharges[139] = +2.2479285836168459e-02;
refCharges[140] = -1.6743086597226880e-02;
refCharges[141] = -1.6618487844529638e-02;
refCharges[142] = +2.2856823680214858e-02;
refCharges[143] = +2.2492092346503741e-02;
refCharges[144] = -1.6477685102592371e-02;
refCharges[145] = -1.6512577357121829e-02;
refCharges[146] = +2.2372339894672359e-02;
refCharges[147] = +2.2669314072663600e-02;
refCharges[148] = -1.6522437543560801e-02;
refCharges[149] = -1.6360961935597891e-02;
refCharges[150] = +2.2512810812382239e-02;
refCharges[151] = +2.2801539619727380e-02;
refCharges[152] = -1.6329444211522159e-02;
refCharges[153] = -1.6329025286116121e-02;
refCharges[154] = +2.2456030249777138e-02;
refCharges[155] = +2.2620307687825199e-02;
refCharges[156] = -1.6665050502379330e-02;
refCharges[157] = -1.6851643488881522e-02;
refCharges[158] = +2.2801405267898620e-02;
refCharges[159] = +2.2523823688088869e-02;
refCharges[160] = -1.6789508111554420e-02;
refCharges[161] = -1.6772440301883480e-02;
refCharges[162] = +2.2436812269334801e-02;
refCharges[163] = +2.2500844608142369e-02;
refCharges[164] = -1.6607454675213788e-02;
refCharges[165] = -1.6662862588347691e-02;
refCharges[166] = +2.3061953735331979e-02;
refCharges[167] = +2.2420041249069420e-02;
refCharges[168] = -1.6442468902598331e-02;
refCharges[169] = -1.6373974620792389e-02;
refCharges[170] = +2.2506564895824501e-02;
refCharges[171] = +2.2330251806451130e-02;
refCharges[172] = -1.6262436738166370e-02;
refCharges[173] = -1.6465942676715650e-02;
refCharges[174] = +2.2557241174403320e-02;
refCharges[175] = +2.2598384980842410e-02;
refCharges[176] = -1.6602518392599359e-02;
refCharges[177] = -1.6780921960624421e-02;
refCharges[178] = +2.2555095230787529e-02;
refCharges[179] = +2.2473577774587541e-02;
refCharges[180] = -1.6799623059318869e-02;
refCharges[181] = -1.6719094510015291e-02;
refCharges[182] = +2.2463872264168110e-02;
refCharges[183] = +2.2158574110333760e-02;
refCharges[184] = -1.6787996591290471e-02;
refCharges[185] = -1.6678466135349231e-02;
refCharges[186] = +2.2487542755574061e-02;
refCharges[187] = +2.2682318358822080e-02;
refCharges[188] = -1.6532253979803770e-02;
refCharges[189] = -1.6537689040277550e-02;
refCharges[190] = +2.2397865979300109e-02;
refCharges[191] = +2.2530311702053791e-02;
refCharges[192] = -1.6441686316765170e-02;
refCharges[193] = -1.6482817053556979e-02;
refCharges[194] = +2.2661124361437471e-02;
refCharges[195] = +2.2785037390217710e-02;
refCharges[196] = -1.6647074395901011e-02;
refCharges[197] = -1.6743630420751301e-02;
refCharges[198] = +2.2618145322396161e-02;
refCharges[199] = +2.2781109882181839e-02;
refCharges[200] = -3.1260449801447910e-03;
refCharges[201] = -3.9755758820159120e-03;
refCharges[202] = +2.4128840318321378e-02;
refCharges[203] = +1.4125134562419230e-02;
refCharges[204] = -1.0117743672496200e-03;
refCharges[205] = +1.3972215520673200e-03;
refCharges[206] = -6.5385491686404423e-02;
refCharges[207] = +9.6780963964089532e-03;
refCharges[208] = -4.6085391670224179e-04;
refCharges[209] = -4.1629218495889556e-03;
refCharges[210] = +3.2254347858849211e-03;
refCharges[211] = -2.1103308683728901e-02;
refCharges[212] = -5.2642789635138579e-04;
refCharges[213] = -3.5405809282116440e-03;
refCharges[214] = -3.8489771827645608e-03;
refCharges[215] = +1.5360402337986310e-02;
refCharges[216] = -2.5544605539984801e-03;
refCharges[217] = -2.0684195430053288e-03;
refCharges[218] = +5.8307075868129909e-04;
refCharges[219] = +1.7640048374411819e-02;
refCharges[220] = -4.1300686775510367e-03;
refCharges[221] = -1.6717139996490131e-03;
refCharges[222] = +1.6108853805671178e-02;
refCharges[223] = -8.0813669917693910e-04;
refCharges[224] = -3.2129528935248971e-03;
refCharges[225] = -2.9720717681279581e-03;
refCharges[226] = +8.1870826444767134e-03;
refCharges[227] = +2.6992805808386519e-02;
refCharges[228] = -1.5237258995953191e-03;
refCharges[229] = -1.7214171980898670e-03;
refCharges[230] = -2.9648012794794482e-02;
refCharges[231] = +1.1416123132786740e-03;
refCharges[232] = -2.9735613844430230e-03;
refCharges[233] = -3.4725001467585258e-03;
refCharges[234] = +1.7230967850137609e-02;
refCharges[235] = +1.6865020887781950e-02;
refCharges[236] = -3.4729525693892290e-03;
refCharges[237] = -1.1522034456148880e-03;
refCharges[238] = +1.4746778513102550e-02;
refCharges[239] = +1.5384834813104681e-02;
refCharges[240] = +1.0288900352376860e-03;
refCharges[241] = +8.6332488670297748e-04;
refCharges[242] = -5.3621819184501887e-02;
refCharges[243] = -1.4796691690445349e-02;
refCharges[244] = -4.5409463365950388e-04;
refCharges[245] = -4.3821454216192556e-03;
refCharges[246] = +2.1621722095396579e-02;
refCharges[247] = -1.1542031344965850e-02;
refCharges[248] = -2.6011493024509012e-03;
refCharges[249] = -1.0493590345216860e-03;
refCharges[250] = +1.0348600485633250e-02;
refCharges[251] = -1.8063987842559429e-02;
refCharges[252] = -3.1625211689452729e-03;
refCharges[253] = -2.6446366949805520e-03;
refCharges[254] = +2.1844750202058168e-02;
refCharges[255] = +4.6038129903204052e-03;
refCharges[256] = -2.2496579138780999e-03;
refCharges[257] = -1.2121885538112860e-03;
refCharges[258] = -4.7229648553686929e-02;
refCharges[259] = +2.3462598670540452e-03;
refCharges[260] = -1.7384468891913261e-03;
refCharges[261] = -4.1464839750167074e-03;
refCharges[262] = -5.3099370109384869e-03;
refCharges[263] = +1.6657682534132759e-02;
refCharges[264] = -1.5773996877606390e-03;
refCharges[265] = +9.6495359980945270e-04;
refCharges[266] = -5.5428110432873767e-02;
refCharges[267] = +9.6609029683694496e-03;
refCharges[268] = -1.6776962836995691e-03;
refCharges[269] = -3.3341083243714539e-03;
refCharges[270] = +1.4850441997387710e-02;
refCharges[271] = +1.4057691989563491e-02;
refCharges[272] = -3.4343949737653950e-03;
refCharges[273] = -1.7567658065573090e-03;
refCharges[274] = +9.2851455028549641e-03;
refCharges[275] = +7.1827990779300592e-03;
refCharges[276] = -2.0154433090011012e-03;
refCharges[277] = -3.1229784770084859e-03;
refCharges[278] = -1.0126762439657809e-02;
refCharges[279] = +5.6365634313695206e-03;
refCharges[280] = -3.5340396163233909e-03;
refCharges[281] = -3.9897923641483996e-03;
refCharges[282] = +1.5894026657291109e-02;
refCharges[283] = +4.6332261232073818e-02;
refCharges[284] = -2.4290775767156401e-03;
refCharges[285] = -1.8518070414957530e-03;
refCharges[286] = -1.3178323418393589e-02;
refCharges[287] = -9.0007671086284758e-03;
refCharges[288] = -6.2329651312640960e-04;
refCharges[289] = +1.8497237269583791e-04;
refCharges[290] = +1.6733801338747491e-02;
refCharges[291] = -1.8229084100360490e-02;
refCharges[292] = -2.6121182262507730e-03;
refCharges[293] = -3.0672801740118218e-03;
refCharges[294] = -6.1632293696291598e-03;
refCharges[295] = -3.0557938481373281e-02;
refCharges[296] = -8.3900909938266187e-04;
refCharges[297] = -2.2371905993963381e-03;
refCharges[298] = -1.3656327418989740e-02;
refCharges[299] = -1.8476168977323518e-02;
......@@ -31,6 +31,7 @@ SKIP_METHODS = [('State', 'getPositions'),
('CalcAmoebaVdwForceKernel',),
('CalcAmoebaWcaDispersionForceKernel',),
('CalcCMAPTorsionForceKernel',),
('CalcConstantPotentialForceKernel',),
('CalcCustomBondForceKernel',),
('CalcCustomCompoundBondForceKernel',),
('CalcCustomExternalForceKernel',),
......@@ -50,6 +51,7 @@ SKIP_METHODS = [('State', 'getPositions'),
('ConstraintInfo',),
('CudaKernelFactory',),
('HipKernelFactory',),
('ElectrodeInfo',),
('ExceptionInfo',),
('ExclusionInfo',),
('FunctionInfo',),
......@@ -115,6 +117,7 @@ NO_OUTPUT_ARGS = [('LocalEnergyMinimizer', 'minimize', 'context'),
('AmoebaMultipoleForce', 'getInducedDipoles', 'context'),
('AmoebaMultipoleForce', 'getLabFramePermanentDipoles', 'context'),
('AmoebaMultipoleForce', 'getTotalDipoles', 'context'),
('ConstantPotentialForce', 'getCharges', 'context'),
('HippoNonbondedForce', 'addParticle', 'dipole'),
('HippoNonbondedForce', 'addParticle', 'quadrupole'),
('HippoNonbondedForce', 'getInducedDipoles', 'context'),
......@@ -338,6 +341,30 @@ UNITS = {
("CMAPTorsionForce", "setMapParameters") : (None, (None, None, "unit.kilojoule_per_mole")),
("CMAPTorsionForce", "getTorsionParameters") : (None, ()),
("CMMotionRemover", "getFrequency") : (None, ()),
("ConstantPotentialForce", "getPMEParameters") : (None, ("unit.nanometer**-1", None, None, None)),
("ConstantPotentialForce", "setPMEParameters") : (None, ("unit.nanometer**-1", None, None, None)),
("ConstantPotentialForce", "addException") : (None, (None, None, "unit.elementary_charge*unit.elementary_charge")),
("ConstantPotentialForce", "getExceptionParameters") : (None, (None, None, "unit.elementary_charge*unit.elementary_charge")),
("ConstantPotentialForce", "setExceptionParameters") : (None, (None, None, None, "unit.elementary_charge*unit.elementary_charge")),
("ConstantPotentialForce", "addParticle") : (None, ("unit.elementary_charge",)),
("ConstantPotentialForce", "getParticleParameters") : ("unit.elementary_charge", ()),
("ConstantPotentialForce", "setParticleParameters") : (None, (None, "unit.elementary_charge",)),
("ConstantPotentialForce", "getConstantPotentialMethod") : (None, ()),
("ConstantPotentialForce", "setConstantPotentialMethod") : (None, (None,)),
("ConstantPotentialForce", "getUsePreconditioner") : (None, ()),
("ConstantPotentialForce", "setUsePreconditioner") : (None, (None,)),
("ConstantPotentialForce", "getCGErrorTolerance") : ("unit.kilojoule_per_mole/unit.elementary_charge", ()),
("ConstantPotentialForce", "setCGErrorTolerance") : (None, ("unit.kilojoule_per_mole/unit.elementary_charge",)),
("ConstantPotentialForce", "addElectrode") : (None, (None, "unit.kilojoule_per_mole/unit.elementary_charge", "unit.nanometer", "unit.nanometer**-1")),
("ConstantPotentialForce", "getElectrodeParameters") : (None, (None, "unit.kilojoule_per_mole/unit.elementary_charge", "unit.nanometer", "unit.nanometer**-1")),
("ConstantPotentialForce", "setElectrodeParameters") : (None, (None, None, "unit.kilojoule_per_mole/unit.elementary_charge", "unit.nanometer", "unit.nanometer**-1")),
("ConstantPotentialForce", "getUseChargeConstraint") : (None, ()),
("ConstantPotentialForce", "setUseChargeConstraint") : (None, (None,)),
("ConstantPotentialForce", "getChargeConstraintTarget") : ("unit.elementary_charge", ()),
("ConstantPotentialForce", "setChargeConstraintTarget") : (None, ("unit.elementary_charge",)),
("ConstantPotentialForce", "getExternalField") : ("unit.kilojoule_per_mole/(unit.nanometer*unit.elementary_charge)", ()),
("ConstantPotentialForce", "setExternalField") : (None, ("unit.kilojoule_per_mole/(unit.nanometer*unit.elementary_charge)",)),
("ConstantPotentialForce", "getCharges") : ("unit.elementary_charge", ()),
("CustomAngleForce", "getNumPerAngleParameters") : (None, ()),
("CustomAngleForce", "getNumGlobalParameters") : (None, ()),
("CustomAngleForce", "getEnergyFunction") : (None, ()),
......
......@@ -189,6 +189,186 @@ class TestAPIUnits(unittest.TestCase):
force.setNonbondedMethod(NonbondedForce.LJPME)
self.assertTrue(force.usesPeriodicBoundaryConditions())
def testConstantPotentialForce(self):
""" Tests the ConstantPotentialForce API features """
force = ConstantPotentialForce()
force.addParticle(1.0)
force.addParticle(1.0*coulomb)
self.assertEqual(force.getNumParticles(), 2)
charge = force.getParticleParameters(0)
self.assertAlmostEqualUnit(charge, 1.0*elementary_charge)
self.assertIs(charge.unit, elementary_charge)
charge = force.getParticleParameters(1)
self.assertAlmostEqualUnit(charge, 1.0*coulomb)
self.assertIs(charge.unit, elementary_charge)
force.setParticleParameters(0, 2.0*coulomb)
force.setParticleParameters(1, 2.0)
charge = force.getParticleParameters(0)
self.assertAlmostEqualUnit(charge, 2.0*coulomb)
charge = force.getParticleParameters(1)
self.assertAlmostEqualUnit(charge, 2.0*elementary_charge)
force.addException(0, 1, 1.0)
force.addException(1, 2, 1.0*coulomb*coulomb)
self.assertEqual(force.getNumExceptions(), 2)
index1, index2, chargeProd = force.getExceptionParameters(0)
self.assertEqual(index1, 0)
self.assertEqual(index2, 1)
self.assertAlmostEqualUnit(chargeProd, 1.0*elementary_charge*elementary_charge)
self.assertIs(chargeProd.unit, elementary_charge*elementary_charge)
index1, index2, chargeProd = force.getExceptionParameters(1)
self.assertEqual(index1, 1)
self.assertEqual(index2, 2)
self.assertAlmostEqualUnit(chargeProd, 1.0*coulomb*coulomb)
self.assertIs(chargeProd.unit, elementary_charge*elementary_charge)
force.setExceptionParameters(0, 3, 4, 2.0*coulomb*coulomb)
force.setExceptionParameters(1, 5, 6, 2.0)
index1, index2, chargeProd = force.getExceptionParameters(0)
self.assertEqual(index1, 3)
self.assertEqual(index2, 4)
self.assertAlmostEqualUnit(chargeProd, 2.0*coulomb*coulomb)
self.assertIs(chargeProd.unit, elementary_charge*elementary_charge)
index1, index2, chargeProd = force.getExceptionParameters(1)
self.assertEqual(index1, 5)
self.assertEqual(index2, 6)
self.assertAlmostEqualUnit(chargeProd, 2.0*elementary_charge*elementary_charge)
self.assertIs(chargeProd.unit, elementary_charge*elementary_charge)
force.addElectrode((0, 1, 2), 1.0, 1.0, 1.0)
force.addElectrode((3, 4, 5), 1.0*kilocalorie_per_mole/coulomb, 1.0*angstrom, 1.0/angstrom)
self.assertEqual(force.getNumElectrodes(), 2)
indices, potential, gaussianWidth, thomasFermiScale = force.getElectrodeParameters(0)
self.assertEqual(set(indices), {0, 1, 2})
self.assertAlmostEqualUnit(potential, 1.0*kilojoule_per_mole/elementary_charge)
self.assertAlmostEqualUnit(gaussianWidth, 1.0*nanometer)
self.assertAlmostEqualUnit(thomasFermiScale, 1.0/nanometer)
self.assertIs(potential.unit, kilojoule_per_mole/elementary_charge)
self.assertIs(gaussianWidth.unit, nanometer)
self.assertIs(thomasFermiScale.unit, nanometer**-1)
indices, potential, gaussianWidth, thomasFermiScale = force.getElectrodeParameters(1)
self.assertEqual(set(indices), {3, 4, 5})
self.assertAlmostEqualUnit(potential, 1.0*kilocalorie_per_mole/coulomb)
self.assertAlmostEqualUnit(gaussianWidth, 1.0*angstrom)
self.assertAlmostEqualUnit(thomasFermiScale, 1.0/angstrom)
self.assertIs(potential.unit, kilojoule_per_mole/elementary_charge)
self.assertIs(gaussianWidth.unit, nanometer)
self.assertIs(thomasFermiScale.unit, nanometer**-1)
force.setElectrodeParameters(0, (6, 7, 8), 2.0*kilocalorie_per_mole/coulomb, 2.0*angstrom, 2.0/angstrom)
force.setElectrodeParameters(1, (9, 10, 11), 2.0, 2.0, 2.0)
indices, potential, gaussianWidth, thomasFermiScale = force.getElectrodeParameters(0)
self.assertEqual(set(indices), {6, 7, 8})
self.assertAlmostEqualUnit(potential, 2.0*kilocalorie_per_mole/coulomb)
self.assertAlmostEqualUnit(gaussianWidth, 2.0*angstrom)
self.assertAlmostEqualUnit(thomasFermiScale, 2.0/angstrom)
indices, potential, gaussianWidth, thomasFermiScale = force.getElectrodeParameters(1)
self.assertEqual(set(indices), {9, 10, 11})
self.assertAlmostEqualUnit(potential, 2.0*kilojoule_per_mole/elementary_charge)
self.assertAlmostEqualUnit(gaussianWidth, 2.0*nanometer)
self.assertAlmostEqualUnit(thomasFermiScale, 2.0/nanometer)
force.setCutoffDistance(2.0)
cutoffDistance = force.getCutoffDistance()
self.assertAlmostEqualUnit(cutoffDistance, 2.0*nanometer)
self.assertIs(cutoffDistance.unit, nanometer)
force.setCutoffDistance(2.0*angstrom)
cutoffDistance = force.getCutoffDistance()
self.assertAlmostEqualUnit(cutoffDistance, 2.0*angstrom)
self.assertIs(cutoffDistance.unit, nanometer)
force.setEwaldErrorTolerance(1e-4)
self.assertEqual(force.getEwaldErrorTolerance(), 1e-4)
force.setEwaldErrorTolerance(2e-4)
self.assertEqual(force.getEwaldErrorTolerance(), 2e-4)
force.setPMEParameters(1.0, 10, 10, 10)
alpha, nx, ny, nz = force.getPMEParameters()
self.assertAlmostEqualUnit(alpha, 1.0/nanometer)
self.assertEqual(nx, 10)
self.assertEqual(ny, 10)
self.assertEqual(nz, 10)
self.assertIs(alpha.unit, nanometer**-1)
force.setPMEParameters(1.0/angstrom, 20, 20, 20)
alpha, nx, ny, nz = force.getPMEParameters()
self.assertAlmostEqualUnit(alpha, 1.0/angstrom)
self.assertEqual(nx, 20)
self.assertEqual(ny, 20)
self.assertEqual(nz, 20)
self.assertIs(alpha.unit, nanometer**-1)
self.assertTrue(force.usesPeriodicBoundaryConditions())
force.setExceptionsUsePeriodicBoundaryConditions(False)
self.assertFalse(force.getExceptionsUsePeriodicBoundaryConditions())
force.setExceptionsUsePeriodicBoundaryConditions(True)
self.assertTrue(force.getExceptionsUsePeriodicBoundaryConditions())
force.setConstantPotentialMethod(ConstantPotentialForce.CG)
self.assertEqual(force.getConstantPotentialMethod(), ConstantPotentialForce.CG)
force.setConstantPotentialMethod(ConstantPotentialForce.Matrix)
self.assertEqual(force.getConstantPotentialMethod(), ConstantPotentialForce.Matrix)
force.setUsePreconditioner(False)
self.assertFalse(force.getUsePreconditioner())
force.setUsePreconditioner(True)
self.assertTrue(force.getUsePreconditioner())
force.setUseChargeConstraint(False)
self.assertFalse(force.getUseChargeConstraint())
force.setUseChargeConstraint(True)
self.assertTrue(force.getUseChargeConstraint())
force.setChargeConstraintTarget(1.0)
target = force.getChargeConstraintTarget()
self.assertAlmostEqualUnit(target, 1.0*elementary_charge)
self.assertIs(target.unit, elementary_charge)
force.setChargeConstraintTarget(1.0*coulomb)
target = force.getChargeConstraintTarget()
self.assertAlmostEqualUnit(target, 1.0*coulomb)
self.assertIs(target.unit, elementary_charge)
force.setCGErrorTolerance(1.0)
target = force.getCGErrorTolerance()
self.assertAlmostEqualUnit(target, 1.0*kilojoule_per_mole/elementary_charge)
self.assertIs(target.unit, kilojoule_per_mole/elementary_charge)
force.setCGErrorTolerance(1.0*kilocalorie_per_mole/coulomb)
target = force.getCGErrorTolerance()
self.assertAlmostEqualUnit(target, 1.0*kilocalorie_per_mole/coulomb)
self.assertIs(target.unit, kilojoule_per_mole/elementary_charge)
force.setExternalField(Vec3(1.0, 2.0, 3.0))
field_x, field_y, field_z = force.getExternalField()
self.assertAlmostEqualUnit(field_x, 1.0*kilojoule_per_mole/(nanometer*elementary_charge))
self.assertAlmostEqualUnit(field_y, 2.0*kilojoule_per_mole/(nanometer*elementary_charge))
self.assertAlmostEqualUnit(field_z, 3.0*kilojoule_per_mole/(nanometer*elementary_charge))
self.assertIs(field_x.unit, kilojoule_per_mole/(nanometer*elementary_charge))
self.assertIs(field_y.unit, kilojoule_per_mole/(nanometer*elementary_charge))
self.assertIs(field_z.unit, kilojoule_per_mole/(nanometer*elementary_charge))
force.setExternalField(Vec3(1.0, 2.0, 3.0)*kilocalorie_per_mole/(angstrom*coulomb))
field_x, field_y, field_z = force.getExternalField()
self.assertAlmostEqualUnit(field_x, 1.0*kilocalorie_per_mole/(angstrom*coulomb))
self.assertAlmostEqualUnit(field_y, 2.0*kilocalorie_per_mole/(angstrom*coulomb))
self.assertAlmostEqualUnit(field_z, 3.0*kilocalorie_per_mole/(angstrom*coulomb))
self.assertIs(field_x.unit, kilojoule_per_mole/(nanometer*elementary_charge))
self.assertIs(field_y.unit, kilojoule_per_mole/(nanometer*elementary_charge))
self.assertIs(field_z.unit, kilojoule_per_mole/(nanometer*elementary_charge))
system = System()
system.addParticle(1.0)
system.addParticle(1.0)
force = ConstantPotentialForce()
force.addParticle(2.0*elementary_charge)
force.addParticle(0.0*elementary_charge)
force.addElectrode((1,), 0.0, 1.0, 0.0)
force.setUseChargeConstraint(True)
system.addForce(force)
context = Context(system, VerletIntegrator(0.001))
context.setPositions([[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
charge1, charge2 = force.getCharges(context)
self.assertAlmostEqualUnit(charge1, 2.0*elementary_charge)
self.assertAlmostEqualUnit(charge2, -2.0*elementary_charge)
self.assertIs(charge1.unit, elementary_charge)
self.assertIs(charge2.unit, elementary_charge)
def testCmapForce(self):
""" Tests the CMAPTorsionForce API features """
map1 = [random.random() for i in range(24*24)]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment