package com.srbenoit.modeling.grid; import com.srbenoit.math.grapher.Graphable; import com.srbenoit.math.grapher.Grapher; /** * A class that precomputes soft-sphere forces and energies at some number of discrete points then * returns an energy or force magnitude based on a square of the ratio of actual distance to * equilibrium distance. For any distance ratio greater than 1, the class returns zero energy and * force. * *
u = dist / EQ_DIST * *
E = WELL_DEPTH [ (1 / u)^12 - 1 ] * *
EQ_DIST * |F| = 12 (WELL_DEPTH / u) (1 / u)^12 where force is directed away from the particle
* (positive forces are repulsive).
*/
public class FastSoftSphere implements Graphable {
/** the number of discrete points to use in the representation of the potential */
private final static int NUM_POINTS = 500;
/** the default domain for graphing the function */
private final double[] domain;
/** the default range for graphing the function */
private final double[] range;
/** the precomputed energies */
private final double[] energies;
/** the precomputed forces */
private final double[] forces;
/**
* Constructs a new FastSoftSphere
.
*
* @param wellDepth the potential well depth.
*/
public FastSoftSphere(final double wellDepth) {
double uVal;
double square;
double sixth;
double twelfth;
int last;
this.energies = new double[NUM_POINTS];
this.forces = new double[NUM_POINTS];
// Compute energies
for (int i = 0; i < NUM_POINTS; i++) {
// if dist ranges from 0 to EQ_DIST, u ranges from 0 to 1
uVal = (i + 0.5) / NUM_POINTS;
square = 1 / uVal;
sixth = square * square * square;
twelfth = sixth * sixth;
this.energies[i] = wellDepth * (square - 1);
this.forces[i] = 12 * wellDepth * square / uVal;
}
// Now adjust so the last term is zero
last = NUM_POINTS - 1;
for (int i = 0; i < NUM_POINTS; i++) {
this.forces[i] -= this.forces[last];
}
this.domain = new double[] { 0, 1.5 };
this.range = new double[] { -wellDepth, 30 * wellDepth };
}
/**
* Computes the energy given a ratio of distance / equilibrium distance.
*
* @param uVal the square of the ratio of actual distance to equilibrium distance
* @return the energy
*/
public double energy(final double uVal) {
int index;
index = (int) (uVal * NUM_POINTS);
if (index < 0) {
index = 0;
} else if (index >= NUM_POINTS) {
index = NUM_POINTS - 1;
}
return this.energies[index];
}
/**
* Computes the force given a ratio of distance / equilibrium distance.
*
* @param uVal the square of the ratio of actual distance to equilibrium distance
* @return the force
*/
public double forceTimesEqDist(final double uVal) {
int index;
index = (int) (uVal * NUM_POINTS);
if (index < 0) {
index = 0;
} else if (index >= NUM_POINTS) {
index = NUM_POINTS - 1;
}
return this.forces[index];
}
/**
* Gets the number of dimensions of the graph (2 for a function of a single value).
*
* @return the number of dimensions of the graph
*/
public int graphDimensions() {
return 2;
}
/**
* Gets a default domain over which the graph will show the main features of the function. This
* domain should be computed based on known attributes of the function.
*
* @return a two-double array containing the left and right endpoints of the default domain
*/
public double[] defaultDomain() {
return this.domain.clone();
}
/**
* Gets a default range over which the graph will show the main features of the function. This
* range should be computed based on known attributes of the function.
*
* @return a two-double array containing the lower and upper limits of the default range
*/
public double[] defaultRange() {
return this.range.clone();
}
/**
* Computes the graph values at a coordinate or coordinates. The number of coordinates needed
* is one less than the dimension.
*
* @param coordinates the list of coordinates
* @return the graph values at that location
*/
public double valueAt(final double... coordinates) {
// return energy(coordinates[0]);
return forceTimesEqDist(coordinates[0]);
}
/**
* Main method to graph the force vs. distance.
*
* @param args command-line arguments
*/
public static void main(final String... args) {
FastSoftSphere obj;
Grapher grapher;
obj = new FastSoftSphere(1);
grapher = new Grapher(500, 500);
grapher.graph(obj);
grapher.showInFrame("Fast Soft Sphere");
}
}