Skip to content

Commit

Permalink
The Rydberg potential class implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Amphiluke committed May 19, 2017
1 parent c33fd77 commit 8df28f6
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 47 deletions.
87 changes: 46 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Potprox uses the [method of least squares](https://en.wikipedia.org/wiki/Least_s

* The Lennard-Jones potential
* The Morse potential
* The Rydberg potential

More potentials will be provided with future releases.

Expand Down Expand Up @@ -64,13 +65,15 @@ let data = [
// Approximate with the Morse potential
let morse = potprox.Morse.from(data);
console.log("Morse potential parameters:");
console.log(`d0 = ${m.d0}; r0 = ${m.r0}; a = ${m.a}`);
console.log("Morse potential parameters:", morse.toJSON());
// Approximate with the Rydberg potential
let ry = potprox.Rydberg.from(data);
console.log("Rydberg potential parameters:", ry.toJSON());
// Approximate with the Lennard-Jones potential
let lj = potprox.LennardJones.from(data);
console.log("Lennard-Jones potential parameters:");
console.log(`epsilon = ${lj.epsilon}; sigma = ${lj.sigma}`);
console.log("Lennard-Jones potential parameters:", lj.toJSON());
```

## API
Expand All @@ -80,79 +83,81 @@ console.log(`epsilon = ${lj.epsilon}; sigma = ${lj.sigma}`);
The potprox module exports an object with potential names as keys and potential classes as values.

```javascript
console.log(potprox); // => Object {LennardJones: <class>, Morse: <class>}
console.log(potprox); // => Object {LennardJones: <class>, Morse: <class>, ...}
```

### The `potprox.LennardJones` class

The `LennardJones` class instance represents the Lennard-Jones potential with the given parameters `epsilon` and `sigma`.

![V(r)=4*epsilon((sigma/r)^12-(sigma/r)^6)](https://wikimedia.org/api/rest_v1/media/math/render/svg/026d58558ad6588bea3419a152c7f414437c0a31)

#### The `LennardJones` constructor
![V(r)=4*epsilon((sigma/r)^12-(sigma/r)^6)](https://latex.codecogs.com/svg.latex?V(r)=4\varepsilon\left[\left(\frac{\sigma}{r}\right)^{12}-\left(\frac{\sigma}{r}\right)^{6}\right])

You may instantiate the LennardJones class as follows:

```javascript
let lj = new potprox.LennardJones({epsilon: 0.041, sigma: 4.5});
```

#### `LennardJones.from(data)`

The static method `from` creates an instance of the `LennardJones` class with potential parameters obtained via the least squares approximation procedure. The method expects a single argument, an array of objects `{r: Number, e: Number}`, where `r` is an interatomic distance, and `e` is the corresponding binding energy. Refer the [Usage](#usage) section for an example.
#### `LennardJones.epsilon`
The `epsilon` parameter of the potential. You provide this parameter during instantiation but you can also change it at any time later on.
#### `LennardJones.sigma`
### The `potprox.Morse` class

The `sigma` parameter of the potential. You provide this parameter during instantiation but you can also change it at any time later on.
The `Morse` class instance represents the Morse potential with the given parameters `d0`, `r0`, and `a` (which are often referenced to as *D<sub>e</sub>*, *r<sub>e</sub>*, and *α* respectively).

#### `LennardJones.at(r)`
![V(r)=-d0+d0(1-exp(-a*(r-r0)))^2](https://latex.codecogs.com/gif.latex?V(r)=-D_{0}&plus;D_{0}\left[1-\exp\left(-a\left(r-r_{0}\right)\right)\right]^{2})

Calculates the value of the Lennard-Jones potential for the given interatomic distance.
You may instantiate the Morse class as follows:

```javascript
let lj = new potprox.LennardJones({epsilon: 0.041, sigma: 4.5});
console.log(lj.at(6.0)); // => -0.02399355483055115
let morse = new potprox.Morse({d0: 0.0368, r0: 5.316, a: 0.867});
```

### The `potprox.Morse` class
### The `potprox.Rydberg` class

The `Morse` class instance represents the Morse potential with the given parameters `d0`, `r0`, and `a` (which are often referenced as *D<sub>e</sub>*, *r<sub>e</sub>*, and *α* respectively).
The `Rydberg` class instance represents the Rydberg potential with the given parameters `d0`, `r0`, and `b`.

![V(r)=d0((1-exp(-a*(r-r0)))^2-1)](https://wikimedia.org/api/rest_v1/media/math/render/svg/ffa35165dc39b206bcb0f80840214b92a75de130)
![V(r)=d0((1-exp(-a*(r-r0)))^2-1)](https://latex.codecogs.com/gif.latex?V(r)=-D_{0}\left[1&plus;\frac{b}{r_{0}}\left(r-r_{0}\right)\right]\exp\left[-\frac{b}{r_{0}}\left(r-r_{0}\right)\right])

#### The `Morse` constructor
You may instantiate the LennardJones class as follows:
You may instantiate the Rydberg class as follows:

```javascript
let morse = new potprox.Morse({d0: 0.0368, r0: 5.316, a: 0.867});
let rydberg = new potprox.Rydberg({d0: 0.0368, r0: 5.350, b: 6.415});
```

#### `Morse.from(data)`
### Potential class methods

The static method `from` creates an instance of the `Morse` class with potential parameters obtained via the least squares approximation procedure. The method expects a single argument, an array of objects `{r: Number, e: Number}`, where `r` is an interatomic distance, and `e` is the corresponding binding energy. Refer the [Usage](#usage) section for an example.
All the classes in the `potprox` object have a few common methods listed below.

#### `Morse.d0`
#### `from(data)`

The `d0` parameter of the potential. You provide this parameter during instantiation but you can also change it at any time later on.
The *static* method `from` creates an instance of the specific class with potential parameters obtained via the least squares approximation procedure. The method expects a single argument, an array of objects `{r: Number, e: Number}`, where `r` is an interatomic distance, and `e` is the corresponding binding energy. Refer the [Usage](#usage) section for an example.

#### `Morse.r0`
#### `at(r)`

The `r0` parameter of the potential. You provide this parameter during instantiation but you can also change it at any time later on.
Calculates the value of the potential for the given interatomic distance.

#### `Morse.a`
```javascript
let lj = new potprox.LennardJones({epsilon: 0.041, sigma: 4.5});
console.log(lj.at(6.0)); // => -0.02399355483055115
The `a` parameter of the potential. You provide this parameter during instantiation but you can also change it at any time later on.
let morse = new potprox.Morse({d0: 0.0368, r0: 5.316, a: 0.867});
console.log(morse.at(6.0)); // => -0.029435553046279185
let rydberg = new potprox.Rydberg({d0: 0.0368, r0: 5.350, b: 6.415});
console.log(rydberg.at(6.0)); // => -0.030035419908893232
```

#### `Morse.at(r)`
#### `toJSON()`

Calculates the value of the Morse potential for the given interatomic distance.
Returns an object containing the potential parameters.

```javascript
let lj = new potprox.LennardJones({epsilon: 0.041, sigma: 4.5});
console.log(lj.toJSON()); // => {epsilon: 0.041, sigma: 4.5}
let morse = new potprox.Morse({d0: 0.0368, r0: 5.316, a: 0.867});
console.log(morse.at(6.0)); // => -0.029435553046279185
```
console.log(morse.toJSON()); // => {d0: 0.0368, r0: 5.316, a: 0.867}
let rydberg = new potprox.Rydberg({d0: 0.0368, r0: 5.350, b: 6.415});
console.log(rydberg.toJSON()); // => {d0: 0.0368, r0: 5.350, b: 6.415}
```

Note that the potential parameters are also available as direct instance properties, and you may change them at any time.
184 changes: 182 additions & 2 deletions dist/potprox.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class LennardJones {
let {epsilon, sigma} = this;
return 4 * epsilon * (Math.pow(sigma / r, 12) - Math.pow(sigma / r, 6));
}

toJSON() {
return {epsilon: this.epsilon, sigma: this.sigma};
}
}

module.exports = LennardJones;
Expand Down Expand Up @@ -243,15 +247,191 @@ class Morse {
let factor = 1 - Math.exp(a * (r0 - r));
return d0 * factor * factor - d0;
}

toJSON() {
return {d0: this.d0, r0: this.r0, a: this.a};
}
}

module.exports = Morse;
},{}],3:[function(require,module,exports){
let instanceData = new WeakMap();

class Rydberg {
constructor({d0 = 1, r0 = 1, b = 2} = {}) {
instanceData.set(this, {});
this.d0 = d0;
this.r0 = r0;
this.b = b;
}

/**
* Create an instance of the Rydberg potential via approximation of input data.
* This method performs fast initial approximation and is not very accurate.
* @param {Array.<{r: Number, e: Number}>} data - Coordinates for approximation
* @returns {Rydberg}
* @static
*/
static fastFrom(data) {
if (!Array.isArray(data)) {
throw new TypeError("Approximated data should be an array of points");
}
if (data.length < 3) {
throw new Error("Too little points. Approximation is impossible");
}
data = data.slice().sort((pt1, pt2) => pt1.r - pt2.r);
let d0 = Number.POSITIVE_INFINITY;
let r0 = 1;
for (let {r, e} of data) {
if (e < d0) {
d0 = e;
r0 = r;
}
}
d0 = Math.abs(d0);
let pt1, pt2;
for (let i = 1; i < data.length; i++) {
pt1 = data[i - 1];
pt2 = data[i];
if (pt2.r >= r0 || pt1.e < 0 || pt2.e < 0) {
break;
}
}
let b;
if (pt1 && pt2 && pt1.r < r0 && pt2.r <= r0) {
let sigma = pt1.e * (pt1.r - pt2.r) / (pt2.e - pt1.e) + pt1.r;
if (sigma > 0) {
b = r0 / (r0 - sigma);
}
}
return new Rydberg({d0, r0, b});
}

/**
* Create an instance of the Rydberg potential via approximation of input data.
* This method gives more accurate approximation results than the `fastFrom` method.
* @param {Array.<{r: Number, e: Number}>} data - Coordinates for approximation
* @returns {Rydberg}
* @static
*/
static from(data) {
let rydberg = this.fastFrom(data);
let {d0, r0, b} = rydberg; // initial approximation

// Convergence limits
const d0Lim = d0 / 1000;
const r0Lim = r0 / 1000;
const bLim = b / 1000;

// Deltas
let dd0, dr0, db;

do {
let c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0, c7 = 0, c8 = 0, c9 = 0;
for (let {r, e} of data) {
let factor = b * (r / r0 - 1);
let exp = Math.exp(-factor);
let k = -d0 * (1 + factor) * exp;
let l = (-1 - factor) * exp;
let m = -d0 * b * r / (r0 * r0) * exp * factor;
let n = d0 * factor / b * exp * factor;

c1 += l * l;
c2 += m * l;
c3 += n * l;
c4 += (k - e) * l;
c5 += m * m;
c6 += n * m;
c7 += (k - e) * m;
c8 += n * n;
c9 += (k - e) * n;
}

db = -((c4 - c1 * c7 / c2) - (c4 - c1 * c9 / c3) * ((c2 - c1 * c5 / c2) / (c2 - c1 * c6 / c3))) /
((c3 - c1 * c6 / c2) - (c3 - c1 * c8 / c3) * (c2 - c1 * c5 / c2) / (c2 - c1 * c6 / c3));
dr0 = ((c3 - c1 * c6 / c2) * db + (c4 - c1 * c7 / c2)) / (c1 * c5 / c2 - c2);
dd0 = (-c2 * dr0 - c3 * db - c4) / c1;

d0 += dd0;
r0 += dr0;
b += db;
} while ((Math.abs(dd0) > d0Lim) && (Math.abs(dr0) > r0Lim) && (Math.abs(db) > bLim));

rydberg.d0 = d0;
rydberg.r0 = r0;
rydberg.b = b;
return rydberg;
}

get d0() {
return instanceData.get(this).d0;
}
set d0(value) {
if (!Number.isFinite(value)) {
throw new TypeError("The 'd0' parameter should be a finite number");
}
if (value <= 0) {
throw new RangeError("The 'd0' parameter should be greater than zero");
}
instanceData.get(this).d0 = value;
}

get r0() {
return instanceData.get(this).r0;
}
set r0(value) {
if (!Number.isFinite(value)) {
throw new TypeError("The 'r0' parameter should be a finite number");
}
if (value <= 0) {
throw new RangeError("The 'r0' parameter should be greater than zero");
}
instanceData.get(this).r0 = value;
}

get b() {
return instanceData.get(this).b;
}
set b(value) {
if (!Number.isFinite(value)) {
throw new TypeError("The 'b' parameter should be a finite number");
}
if (value <= 1) {
throw new RangeError("The 'b' parameter should be greater than 1");
}
instanceData.get(this).b = value;
}

/**
* Calculate energy for the given interatomic distance
* @param {Number} r
* @returns {Number}
*/
at(r) {
if (typeof r !== "number") {
throw new TypeError("Distance should be a number");
}
if (r < 0) {
throw new RangeError("Distance shouldn't be less than zero");
}
let {d0, r0, b} = this;
let factor = b * (r - r0) / r0;
return -d0 * (1 + factor) * Math.exp(-factor);
}

toJSON() {
return {d0: this.d0, r0: this.r0, b: this.b};
}
}

module.exports = Rydberg;
},{}],4:[function(require,module,exports){
let potprox = {
LennardJones: require("./potentials/lennard-jones.js"),
Morse: require("./potentials/morse.js")
Morse: require("./potentials/morse.js"),
Rydberg: require("./potentials/rydberg.js")
};

module.exports = potprox;
},{"./potentials/lennard-jones.js":1,"./potentials/morse.js":2}]},{},[3])(3)
},{"./potentials/lennard-jones.js":1,"./potentials/morse.js":2,"./potentials/rydberg.js":3}]},{},[4])(4)
});
Loading

0 comments on commit 8df28f6

Please sign in to comment.