10 Commits

Author SHA1 Message Date
Daniel Bauer
7b39d603bd remove unneccessary parameter in bootstrapping function 2020-09-15 15:32:05 +02:00
Daniel Bauer
465f46b280 fix unit tests 2020-09-15 15:20:40 +02:00
Daniel Bauer
d221fc7195 lock 2020-09-15 14:49:03 +02:00
Daniel Bauer
dc218df051 calculate SE of A directly 2020-09-15 14:48:36 +02:00
Daniel Bauer
1e27cfd457 report standard error (SE) instead of standard deviations 2020-09-15 14:10:48 +02:00
Daniel Bauer
7116142c2a .gitignore 2020-03-11 09:40:31 +01:00
Daniel Bauer
fbdb451f6b print less 2020-03-11 09:40:01 +01:00
Daniel Bauer
d4119b2fae clean code (2) 2020-03-11 09:31:48 +01:00
Daniel Bauer
b9f6b24b20 clean code 2020-03-10 09:44:32 +01:00
Daniel Bauer
5390b089ac remove some code smell 2020-03-09 10:05:36 +01:00
10 changed files with 362 additions and 315 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
target target
reference reference
.idea .idea
*bench.* *bench.*
*.sublime*

183
Cargo.lock generated
View File

@@ -11,6 +11,21 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "addr2line"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@@ -20,6 +35,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "assert_approx_eq"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c07dab4369547dbe5114677b33fbbf724971019f3818172d59a97a61c774ffd"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -33,32 +54,24 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.0" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.45" version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
dependencies = [ dependencies = [
"backtrace-sys", "addr2line",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide",
"object",
"rustc-demangle", "rustc-demangle",
] ]
[[package]]
name = "backtrace-sys"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35"
dependencies = [
"cc",
"libc",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
@@ -71,12 +84,6 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9e1d9f7d49e289f36f19effbf3d5a5e30163ecf9c7a3c9be94d5374dec5b9a" checksum = "aa9e1d9f7d49e289f36f19effbf3d5a5e30163ecf9c7a3c9be94d5374dec5b9a"
[[package]]
name = "cc"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.10" version = "0.1.10"
@@ -85,9 +92,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.0" version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
@@ -108,6 +115,16 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "crossbeam-channel"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
dependencies = [
"crossbeam-utils",
"maybe-uninit",
]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.7.3" version = "0.7.3"
@@ -134,16 +151,6 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "crossbeam-queue"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.7.2" version = "0.7.2"
@@ -157,15 +164,15 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.5.3" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
[[package]] [[package]]
name = "error-chain" name = "error-chain"
version = "0.12.2" version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"version_check", "version_check",
@@ -178,10 +185,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "hermit-abi" name = "gimli"
version = "0.1.8" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
[[package]]
name = "hermit-abi"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -194,9 +207,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.67" version = "0.2.77"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
[[package]] [[package]]
name = "maybe-uninit" name = "maybe-uninit"
@@ -206,28 +219,44 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.5.3" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f"
dependencies = [ dependencies = [
"rustc_version", "autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
dependencies = [
"adler",
"autocfg",
] ]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.12.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
] ]
[[package]] [[package]]
name = "pkg-config" name = "object"
version = "0.3.17" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
[[package]]
name = "pkg-config"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
[[package]] [[package]]
name = "rand" name = "rand"
@@ -259,10 +288,11 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
dependencies = [ dependencies = [
"autocfg",
"crossbeam-deque", "crossbeam-deque",
"either", "either",
"rayon-core", "rayon-core",
@@ -270,12 +300,12 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" checksum = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0"
dependencies = [ dependencies = [
"crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
"crossbeam-queue",
"crossbeam-utils", "crossbeam-utils",
"lazy_static", "lazy_static",
"num_cpus", "num_cpus",
@@ -287,36 +317,12 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"
@@ -334,27 +340,28 @@ dependencies = [
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.7" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.1" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]] [[package]]
name = "wham" name = "wham"
version = "0.9.6" version = "0.9.8"
dependencies = [ dependencies = [
"GSL", "GSL",
"assert_approx_eq",
"clap", "clap",
"error-chain", "error-chain",
"rand", "rand",
@@ -363,9 +370,9 @@ dependencies = [
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu", "winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wham" name = "wham"
version = "0.9.6" version = "0.9.8"
authors = ["Daniel Bauer <bauer@cbs.tu-darmstadt.de>"] authors = ["Daniel Bauer <bauer@cbs.tu-darmstadt.de>"]
description = "An implementation of the weighted histogram analysis method" description = "An implementation of the weighted histogram analysis method"
license = "GPL-3.0" license = "GPL-3.0"
@@ -13,6 +13,9 @@ rand = "0.5.5"
GSL = "1.0.0" GSL = "1.0.0"
rayon = "1.0.3" rayon = "1.0.3"
[dev-dependencies]
assert_approx_eq = "1.1.0"
[profile.release] [profile.release]
opt-level = 2 opt-level = 2

View File

@@ -81,8 +81,8 @@ one can estimate the error as standard deviation between the N bootstrapping run
Autocorrelation Estimates, JCTC, 6(12), 3713-3720*. Autocorrelation Estimates, JCTC, 6(12), 3713-3720*.
To perform bayesian bootstrapping in WHAM, use the ```-bt <RUNS>``` flag to perform <RUNS> individual bootstrapping To perform bayesian bootstrapping in WHAM, use the ```-bt <RUNS>``` flag to perform <RUNS> individual bootstrapping
runs. The error estimates of bin probabilities and free energy will be given as separate column (+/-) in the output file. runs. The error estimates of bin probabilities and free energy will be given as standard error (SE) in a
If no error analysis is performed, these columns are set to 0.0. separate column (+/-) in the output file. If no error analysis is performed, these columns are set to 0.0.
Examples Examples
--- ---

View File

@@ -1,101 +1,101 @@
#coord1 Free Energy +/- Probability +/- #coord1 Free Energy +/- Probability +/-
-3.110177 7.158102 0.476037 0.003494 0.000667 -3.110177 7.158102 0.069244 0.003494 0.000067
-3.047345 5.365727 0.470738 0.007168 0.001353 -3.047345 5.365727 0.068503 0.007168 0.000135
-2.984513 3.873190 0.433120 0.013039 0.002264 -2.984513 3.873190 0.065883 0.013039 0.000226
-2.921681 2.953162 0.441412 0.018855 0.003337 -2.921681 2.953162 0.066856 0.018855 0.000334
-2.858849 1.949554 0.443549 0.028195 0.005014 -2.858849 1.949554 0.066705 0.028195 0.000501
-2.796017 1.391747 0.407397 0.035261 0.005759 -2.796017 1.391747 0.064012 0.035261 0.000576
-2.733186 1.128270 0.380789 0.039189 0.005983 -2.733186 1.128270 0.061522 0.039189 0.000598
-2.670354 0.839970 0.370008 0.043991 0.006526 -2.670354 0.839970 0.060810 0.043991 0.000653
-2.607522 0.624769 0.381081 0.047955 0.007326 -2.607522 0.624769 0.061888 0.047955 0.000733
-2.544690 0.663757 0.389082 0.047211 0.007364 -2.544690 0.663757 0.062566 0.047211 0.000736
-2.481858 1.051932 0.379999 0.040407 0.006156 -2.481858 1.051932 0.061093 0.040407 0.000616
-2.419026 1.463048 0.394914 0.034267 0.005425 -2.419026 1.463048 0.062547 0.034267 0.000543
-2.356194 1.990616 0.335141 0.027734 0.003726 -2.356194 1.990616 0.057022 0.027734 0.000373
-2.293363 2.190692 0.196497 0.025597 0.002016 -2.293363 2.190692 0.044029 0.025597 0.000202
-2.230531 2.553036 0.177045 0.022136 0.001571 -2.230531 2.553036 0.041867 0.022136 0.000157
-2.167699 2.572522 0.208798 0.021964 0.001839 -2.167699 2.572522 0.044817 0.021964 0.000184
-2.104867 2.472360 0.168929 0.022863 0.001548 -2.104867 2.472360 0.038778 0.022863 0.000155
-2.042035 2.517562 0.166774 0.022453 0.001501 -2.042035 2.517562 0.030296 0.022453 0.000150
-1.979203 2.469778 0.182308 0.022887 0.001673 -1.979203 2.469778 0.025852 0.022887 0.000167
-1.916372 2.223125 0.405294 0.025266 0.004105 -1.916372 2.223125 0.030799 0.025266 0.000411
-1.853540 2.080157 0.340376 0.026756 0.003651 -1.853540 2.080157 0.024928 0.026756 0.000365
-1.790708 1.793841 0.394974 0.030011 0.004752 -1.790708 1.793841 0.027529 0.030011 0.000475
-1.727876 1.458784 0.335956 0.034326 0.004623 -1.727876 1.458784 0.026130 0.034326 0.000462
-1.665044 0.914441 0.336724 0.042697 0.005764 -1.665044 0.914441 0.024774 0.042697 0.000576
-1.602212 0.303813 0.320695 0.054540 0.007012 -1.602212 0.303813 0.020400 0.054540 0.000701
-1.539380 0.268335 0.330495 0.055321 0.007330 -1.539380 0.268335 0.020423 0.055321 0.000733
-1.476549 0.000000 0.338143 0.061604 0.008351 -1.476549 0.000000 0.020271 0.061604 0.000835
-1.413717 0.537061 0.369220 0.049671 0.007352 -1.413717 0.537061 0.023895 0.049671 0.000735
-1.350885 1.439940 0.381006 0.034586 0.005283 -1.350885 1.439940 0.023678 0.034586 0.000528
-1.288053 2.391838 0.407306 0.023614 0.003856 -1.288053 2.391838 0.025951 0.023614 0.000386
-1.225221 3.779470 0.413629 0.013538 0.002245 -1.225221 3.779470 0.026215 0.013538 0.000224
-1.162389 5.685555 0.432485 0.006305 0.001093 -1.162389 5.685555 0.028543 0.006305 0.000109
-1.099557 7.661896 0.446994 0.002855 0.000512 -1.099557 7.661896 0.030579 0.002855 0.000051
-1.036726 9.946594 0.489990 0.001142 0.000224 -1.036726 9.946594 0.039243 0.001142 0.000022
-0.973894 12.359408 0.544847 0.000434 0.000095 -0.973894 12.359408 0.054067 0.000434 0.000009
-0.911062 14.954655 0.622373 0.000153 0.000038 -0.911062 14.954655 0.066597 0.000153 0.000004
-0.848230 17.742242 0.747233 0.000050 0.000015 -0.848230 17.742242 0.073582 0.000050 0.000002
-0.785398 20.555785 0.921773 0.000016 0.000006 -0.785398 20.555785 0.074644 0.000016 0.000001
-0.722566 22.811160 1.179343 0.000007 0.000003 -0.722566 22.811160 0.078503 0.000007 0.000000
-0.659734 25.178094 1.484376 0.000003 0.000002 -0.659734 25.178094 0.088961 0.000003 0.000000
-0.596903 26.442288 1.565063 0.000002 0.000001 -0.596903 26.442288 0.093509 0.000002 0.000000
-0.534071 27.897565 1.418232 0.000001 0.000000 -0.534071 27.897565 0.091353 0.000001 0.000000
-0.471239 29.062473 1.246738 0.000001 0.000000 -0.471239 29.062473 0.086244 0.000001 0.000000
-0.408407 30.384521 1.231662 0.000000 0.000000 -0.408407 30.384521 0.084285 0.000000 0.000000
-0.345575 31.638454 1.209295 0.000000 0.000000 -0.345575 31.638454 0.084871 0.000000 0.000000
-0.282743 32.817727 1.291637 0.000000 0.000000 -0.282743 32.817727 0.092750 0.000000 0.000000
-0.219911 33.770369 1.323362 0.000000 0.000000 -0.219911 33.770369 0.094479 0.000000 0.000000
-0.157080 34.505503 1.396454 0.000000 0.000000 -0.157080 34.505503 0.095774 0.000000 0.000000
-0.094248 35.431659 1.662548 0.000000 0.000000 -0.094248 35.431659 0.107598 0.000000 0.000000
-0.031416 35.615810 1.766523 0.000000 0.000000 -0.031416 35.615810 0.108959 0.000000 0.000000
0.031416 35.561946 1.799603 0.000000 0.000000 0.031416 35.561946 0.107382 0.000000 0.000000
0.094248 35.382089 1.374764 0.000000 0.000000 0.094248 35.382089 0.096643 0.000000 0.000000
0.157080 34.934827 1.659669 0.000000 0.000000 0.157080 34.934827 0.107624 0.000000 0.000000
0.219911 33.673460 1.317449 0.000000 0.000000 0.219911 33.673460 0.100231 0.000000 0.000000
0.282743 32.731563 1.191975 0.000000 0.000000 0.282743 32.731563 0.096604 0.000000 0.000000
0.345575 31.261855 1.199834 0.000000 0.000000 0.345575 31.261855 0.099036 0.000000 0.000000
0.408407 29.717377 1.339899 0.000000 0.000000 0.408407 29.717377 0.107915 0.000000 0.000000
0.471239 28.076620 1.303458 0.000001 0.000000 0.471239 28.076620 0.104513 0.000001 0.000000
0.534071 26.481097 1.281459 0.000002 0.000001 0.534071 26.481097 0.103164 0.000002 0.000000
0.596903 24.487358 1.251139 0.000003 0.000002 0.596903 24.487358 0.103039 0.000003 0.000000
0.659734 22.344251 1.233967 0.000008 0.000004 0.659734 22.344251 0.100666 0.000008 0.000000
0.722566 20.241543 1.251834 0.000018 0.000009 0.722566 20.241543 0.102150 0.000018 0.000001
0.785398 18.341869 1.241684 0.000039 0.000020 0.785398 18.341869 0.101957 0.000039 0.000002
0.848230 16.261582 1.281159 0.000091 0.000047 0.848230 16.261582 0.105391 0.000091 0.000005
0.911062 14.301801 1.294427 0.000199 0.000103 0.911062 14.301801 0.107389 0.000199 0.000010
0.973894 12.603788 1.270069 0.000394 0.000200 0.973894 12.603788 0.105487 0.000394 0.000020
1.036726 11.249601 1.273360 0.000678 0.000346 1.036726 11.249601 0.106308 0.000678 0.000035
1.099557 10.087886 1.280795 0.001079 0.000554 1.099557 10.087886 0.106741 0.001079 0.000055
1.162389 9.443303 1.266983 0.001398 0.000710 1.162389 9.443303 0.106957 0.001398 0.000071
1.225221 9.152799 1.255009 0.001570 0.000790 1.225221 9.152799 0.105940 0.001570 0.000079
1.288053 9.331937 1.256822 0.001462 0.000736 1.288053 9.331937 0.105860 0.001462 0.000074
1.350885 9.905546 1.251237 0.001161 0.000583 1.350885 9.905546 0.105389 0.001161 0.000058
1.413717 11.042050 1.263816 0.000736 0.000373 1.413717 11.042050 0.105466 0.000736 0.000037
1.476549 12.598167 1.275325 0.000395 0.000202 1.476549 12.598167 0.105119 0.000395 0.000020
1.539380 14.520167 1.280735 0.000183 0.000094 1.539380 14.520167 0.104367 0.000183 0.000009
1.602212 16.569783 1.295384 0.000080 0.000042 1.602212 16.569783 0.104184 0.000080 0.000004
1.665044 18.687390 1.309518 0.000034 0.000018 1.665044 18.687390 0.104276 0.000034 0.000002
1.727876 20.775408 1.356414 0.000015 0.000008 1.727876 20.775408 0.104944 0.000015 0.000001
1.790708 22.905200 1.308568 0.000006 0.000003 1.790708 22.905200 0.101547 0.000006 0.000000
1.853540 24.643852 1.425870 0.000003 0.000002 1.853540 24.643852 0.103914 0.000003 0.000000
1.916372 26.301740 1.362138 0.000002 0.000001 1.916372 26.301740 0.101973 0.000002 0.000000
1.979203 27.372071 1.391716 0.000001 0.000001 1.979203 27.372071 0.101762 0.000001 0.000000
2.042035 28.697726 1.504676 0.000001 0.000000 2.042035 28.697726 0.105177 0.000001 0.000000
2.104867 29.417901 1.369019 0.000000 0.000000 2.104867 29.417901 0.100003 0.000000 0.000000
2.167699 30.008351 1.409081 0.000000 0.000000 2.167699 30.008351 0.100038 0.000000 0.000000
2.230531 30.406016 1.240128 0.000000 0.000000 2.230531 30.406016 0.096233 0.000000 0.000000
2.293363 30.171275 1.179444 0.000000 0.000000 2.293363 30.171275 0.096428 0.000000 0.000000
2.356194 29.884646 1.219365 0.000000 0.000000 2.356194 29.884646 0.108339 0.000000 0.000000
2.419026 29.428153 1.177281 0.000000 0.000000 2.419026 29.428153 0.106679 0.000000 0.000000
2.481858 28.546982 1.351057 0.000001 0.000000 2.481858 28.546982 0.123259 0.000001 0.000000
2.544690 27.757520 1.238695 0.000001 0.000000 2.544690 27.757520 0.108526 0.000001 0.000000
2.607522 26.505787 1.308430 0.000001 0.000001 2.607522 26.505787 0.111134 0.000001 0.000000
2.670354 24.491866 1.039660 0.000003 0.000001 2.670354 24.491866 0.095963 0.000003 0.000000
2.733186 22.320664 0.927893 0.000008 0.000003 2.733186 22.320664 0.096576 0.000008 0.000000
2.796017 20.052723 0.894483 0.000020 0.000007 2.796017 20.052723 0.098813 0.000020 0.000001
2.858849 17.655650 0.893580 0.000052 0.000019 2.858849 17.655650 0.097052 0.000052 0.000002
2.921681 15.471590 0.930897 0.000125 0.000047 2.921681 15.471590 0.100497 0.000125 0.000005
2.984513 13.138167 0.837026 0.000318 0.000107 2.984513 13.138167 0.092102 0.000318 0.000011
3.047345 11.092386 0.674785 0.000722 0.000195 3.047345 11.092386 0.081862 0.000722 0.000020
3.110177 9.065722 0.521230 0.001626 0.000340 3.110177 9.065722 0.072111 0.001626 0.000034

View File

@@ -1,7 +1,7 @@
use rand::{SeedableRng, StdRng, Rng}; use rand::{SeedableRng, StdRng, Rng};
use super::histogram::{Dataset}; use super::histogram::{Dataset};
use super::perform_wham; use super::perform_wham;
use super::Config; use super::{Config,calc_free_energy};
use rgsl::statistics; use rgsl::statistics;
// returns a set of num_windows continious weights by // returns a set of num_windows continious weights by
@@ -20,7 +20,7 @@ fn generate_random_weights(num_windows: usize, rng: &mut StdRng) -> Vec<f64> {
for i in 0..num_windows { for i in 0..num_windows {
weights[i] = rnds[i+1] - rnds[i] weights[i] = rnds[i+1] - rnds[i]
} }
return weights weights
} }
// Generate a random weighted dataset from the given dataset by changing the weights // Generate a random weighted dataset from the given dataset by changing the weights
@@ -32,7 +32,7 @@ fn generate_random_weighted_dataset(ds: Dataset, rng: &mut StdRng) -> Dataset {
// Perform bootstrap error analysis. This runs the WHAM analysis num_runs times on random weighted // Perform bootstrap error analysis. This runs the WHAM analysis num_runs times on random weighted
// datasets. The standard deviation is calculated on the bootstrapped probabilities of each bin. The // datasets. The standard deviation is calculated on the bootstrapped probabilities of each bin. The
// standard deviation of the free eneergy is then deduced by error propagation (A_std = kT*1/P*P_std) // standard deviation of the free eneergy is then deduced by error propagation (A_std = kT*1/P*P_std)
pub fn run_bootstrap(cfg: &Config, ds: Dataset, P: &[f64], num_runs: usize) -> (Vec<f64>,Vec<f64>) { pub fn run_bootstrap(cfg: &Config, ds: Dataset, num_runs: usize) -> (Vec<f64>,Vec<f64>) {
// seed the rng // seed the rng
let mut rng: StdRng = SeedableRng::seed_from_u64(cfg.bootstrap_seed); let mut rng: StdRng = SeedableRng::seed_from_u64(cfg.bootstrap_seed);
@@ -43,16 +43,27 @@ pub fn run_bootstrap(cfg: &Config, ds: Dataset, P: &[f64], num_runs: usize) -> (
perform_wham(cfg, &rnd_weighted_dataset).unwrap().0 perform_wham(cfg, &rnd_weighted_dataset).unwrap().0
}).collect(); }).collect();
// Evaulate standard deviation of P per bin // Standard error (SE) of P per bin
let mut P_std = vec![0.0; ds.num_bins]; // SE = SD/sqrt(n)
let mut P_se = vec![0.0; ds.num_bins];
for bin in 0..ds.num_bins { for bin in 0..ds.num_bins {
let Ps = bootstrapped_Ps.iter().map(|window| window[bin]).collect::<Vec<f64>>(); let Ps = bootstrapped_Ps.iter().map(|window| window[bin]).collect::<Vec<f64>>();
P_std[bin] = statistics::sd(&Ps, 1, num_runs); P_se[bin] = statistics::sd(&Ps, 1, num_runs)/(num_runs as f64).sqrt();
} }
// A_std by error propagation // SE of A
let A_std = P_std.iter().zip(P.iter()).map(|(std,P)| ds.kT*1.0/P*std).collect(); let bootstrapped_As: Vec<Vec<f64>> = (0..num_runs).map(|x| {
(P_std, A_std) let run_Ps = &bootstrapped_Ps[x];
calc_free_energy(&ds, run_Ps)
}).collect();
let mut A_se = vec![0.0; ds.num_bins];
for bin in 0..ds.num_bins {
let As = bootstrapped_As.iter().map(|window| window[bin]).collect::<Vec<f64>>();
A_se[bin] = statistics::sd(&As, 1, num_runs)/(num_runs as f64).sqrt();
}
(P_se, A_se)
} }
#[cfg(tests)] #[cfg(tests)]

View File

@@ -61,7 +61,9 @@ pub struct Dataset {
impl Dataset { impl Dataset {
pub fn new(num_bins: usize, dimens_lengths: Vec<usize>, bin_width: Vec<f64>, hist_min: Vec<f64>, hist_max: Vec<f64>, bias_pos: Vec<f64>, bias_fc: Vec<f64>, kT: f64, histograms: Vec<Histogram>, cyclic: bool) -> Dataset { pub fn new(num_bins: usize, dimens_lengths: Vec<usize>, bin_width: Vec<f64>,
hist_min: Vec<f64>, hist_max: Vec<f64>, bias_pos: Vec<f64>,
bias_fc: Vec<f64>, kT: f64, histograms: Vec<Histogram>, cyclic: bool) -> Dataset {
let num_windows = histograms.len(); let num_windows = histograms.len();
let bias: Vec<f64> = vec![0.0; num_bins*num_windows]; let bias: Vec<f64> = vec![0.0; num_bins*num_windows];
let weights = vec![1.0; num_windows]; let weights = vec![1.0; num_windows];
@@ -92,7 +94,7 @@ impl Dataset {
pub fn new_weighted(ds: Dataset, weights: Vec<f64>) -> Dataset { pub fn new_weighted(ds: Dataset, weights: Vec<f64>) -> Dataset {
Dataset { Dataset {
weights: weights, weights,
..ds ..ds
} }
} }
@@ -105,9 +107,9 @@ impl Dataset {
let mut tmp = bin; let mut tmp = bin;
let mut idx = vec![0; lengths.len()]; let mut idx = vec![0; lengths.len()];
for dimen in (1..lengths.len()).rev() { for dimen in (1..lengths.len()).rev() {
let denom = lengths.iter().take(dimen).fold(1, |s,&x| s*x); let denom: usize = lengths.iter().take(dimen).product();
idx[dimen] = tmp / denom; idx[dimen] = tmp / denom;
tmp = tmp % denom; tmp %= denom;
} }
idx[0] = tmp; idx[0] = tmp;
idx idx
@@ -151,8 +153,7 @@ impl Dataset {
// store exp(U/kT) for better performance // store exp(U/kT) for better performance
bias_sum += 0.5 * bias_fc[i] * dist * dist bias_sum += 0.5 * bias_fc[i] * dist * dist
} }
let bias_sum = (-bias_sum/self.kT).exp(); (-bias_sum/self.kT).exp()
bias_sum
} }
} }
@@ -205,13 +206,13 @@ mod tests {
let ds = build_hist_set(); // k = 10 let ds = build_hist_set(); // k = 10
// 3th element -> x=3.5, x0=3.5 // 3th element -> x=3.5, x0=3.5
assert_delta!(0.134722337796, ds.calc_bias(3, 0), 0.00000001); assert_delta!(0.134_722_337_796, ds.calc_bias(3, 0), 0.000_000_01);
// 8th element -> x=8.5, x0=3.5 // 8th element -> x=8.5, x0=3.5
assert_delta!(1.0, ds.calc_bias(4,0), 0.00000001); assert_delta!(1.0, ds.calc_bias(4,0), 0.000_000_01);
// 1st element -> x=0.5, x0=3.5. non-cyclic! // 1st element -> x=0.5, x0=3.5. non-cyclic!
assert_delta!(0.0, ds.calc_bias(0,0), 0.0000001); assert_delta!(0.0, ds.calc_bias(0,0), 0.000_000_1);
} }
#[test] #[test]
@@ -220,28 +221,28 @@ mod tests {
ds.cyclic = true; ds.cyclic = true;
// 7th element -> x=3.5, x0=3.5 // 7th element -> x=3.5, x0=3.5
assert_delta!(0.134722337796, ds.calc_bias(3, 0), 0.00000001); assert_delta!(0.134_722_337_796, ds.calc_bias(3, 0), 0.000_000_01);
// 8th element -> x=4.5, x0=3.5 // 8th element -> x=4.5, x0=3.5
assert_delta!(1.0, ds.calc_bias(4, 0), 0.00000001); assert_delta!(1.0, ds.calc_bias(4, 0), 0.000_000_01);
// 1th element -> x=0.5, x0=3.5 // 1th element -> x=0.5, x0=3.5
// cyclic flag makes bin 0 neighboring bin 9, so the distance is actually 2 // cyclic flag makes bin 0 neighboring bin 9, so the distance is actually 2
assert_delta!(0.0000000000000117769, ds.calc_bias(0, 0), 0.00000001); assert_delta!(0.000_000_000_000_011_776_9, ds.calc_bias(0, 0), 0.000_000_01);
// 2nd element -> x=1.5, x0=3.5 // 2nd element -> x=1.5, x0=3.5
assert_delta!(0.00000001, ds.calc_bias(1, 0), 0.00000001); assert_delta!(0.000_000_01, ds.calc_bias(1, 0), 0.000_000_01);
} }
#[test] #[test]
fn get_x_for_bin() { fn get_x_for_bin() {
let ds = build_hist_set(); let ds = build_hist_set();
let expected: Vec<f64> = vec![0,1,2,3,4,5,6,7,8].iter() let expected: Vec<f64> = vec![0,1,2,3,4,5,6,7,8].iter()
.map(|x| *x as f64 + 0.5).collect(); .map(|x| *x as f64 + 0.5).collect();
for i in 0..9 { expected.iter().enumerate().for_each(|(i, exp)| {
assert_eq!(expected[i], ds.get_coords_for_bin(i)[0]); assert_approx_eq!(exp, &ds.get_coords_for_bin(i)[0]);
} })
} }
#[test] #[test]
@@ -258,10 +259,10 @@ mod tests {
vec![build_hist(), build_hist()], // hists vec![build_hist(), build_hist()], // hists
false // cyclic false // cyclic
); );
assert_delta!(2.0, ds.get_weighted_bin_count(0), 0.0000000001); assert_delta!(2.0, ds.get_weighted_bin_count(0), 0.000_000_000_1);
assert_delta!(2.0, ds.get_weighted_bin_count(1), 0.0000000001); assert_delta!(2.0, ds.get_weighted_bin_count(1), 0.000_000_000_1);
assert_delta!(6.0, ds.get_weighted_bin_count(2), 0.0000000001); assert_delta!(6.0, ds.get_weighted_bin_count(2), 0.000_000_000_1);
assert_delta!(10.0, ds.get_weighted_bin_count(3), 0.0000000001); assert_delta!(10.0, ds.get_weighted_bin_count(3), 0.000_000_000_1);
assert_delta!(24.0, ds.get_weighted_bin_count(4), 0.0000000001); assert_delta!(24.0, ds.get_weighted_bin_count(4), 0.000_000_000_1);
} }
} }

View File

@@ -35,7 +35,7 @@ pub fn read_data(cfg: &Config) -> Result<Dataset> {
let bin_width: Vec<f64> = (0..cfg.dimens).map(|idx| { let bin_width: Vec<f64> = (0..cfg.dimens).map(|idx| {
(cfg.hist_max[idx] - cfg.hist_min[idx])/(cfg.num_bins[idx] as f64) (cfg.hist_max[idx] - cfg.hist_min[idx])/(cfg.num_bins[idx] as f64)
}).collect(); }).collect();
let num_bins = cfg.num_bins.iter().fold(1, |state, &bins| state*bins); let num_bins = cfg.num_bins.iter().product();
let dimens_length = cfg.num_bins.clone(); let dimens_length = cfg.num_bins.clone();
let f = File::open(&cfg.metadata_file).chain_err(|| "Failed to open metadata file")?; let f = File::open(&cfg.metadata_file).chain_err(|| "Failed to open metadata file")?;
@@ -46,7 +46,7 @@ pub fn read_data(cfg: &Config) -> Result<Dataset> {
let line = l.chain_err(|| "Failed to read line")?; let line = l.chain_err(|| "Failed to read line")?;
// skip comments and empty lines // skip comments and empty lines
if line.starts_with("#") || line.len() == 0 { if line.starts_with('#') || line.is_empty() {
continue; continue;
} }
@@ -67,19 +67,19 @@ pub fn read_data(cfg: &Config) -> Result<Dataset> {
histograms.last().unwrap().num_points), cfg.verbose); histograms.last().unwrap().num_points), cfg.verbose);
// parse bias force constants and positions // parse bias force constants and positions
for i in 1..cfg.dimens+1 { for val in split.iter().skip(1).take(cfg.dimens) {
let pos = split[i].parse() let pos = val.parse()
.chain_err(|| format!("Failed to read bias position in line {} of metadata file", line_num+1))?; .chain_err(|| format!("Failed to read bias position in line {} of metadata file", line_num+1))?;
bias_pos.push(pos); bias_pos.push(pos);
} }
for i in (1+cfg.dimens)..(1+2*cfg.dimens) { for val in split.iter().skip(1+cfg.dimens).take(cfg.dimens) {
let fc = split[i].parse() let fc = val.parse()
.chain_err(|| format!("Failed to read bias fc in line {} of metadata file", line_num+1))?; .chain_err(|| format!("Failed to read bias fc in line {} of metadata file", line_num+1))?;
bias_fc.push(fc); bias_fc.push(fc);
} }
} }
if histograms.len() > 0 { if !histograms.is_empty() {
Ok(Dataset::new(num_bins, dimens_length, bin_width, cfg.hist_min.clone(), cfg.hist_max.clone(), bias_pos, bias_fc, kT, histograms, cfg.cyclic)) Ok(Dataset::new(num_bins, dimens_length, bin_width, cfg.hist_min.clone(), cfg.hist_max.clone(), bias_pos, bias_fc, kT, histograms, cfg.cyclic))
} else { } else {
bail!("Histogram has no datapoints.") bail!("Histogram has no datapoints.")
@@ -91,13 +91,10 @@ pub fn read_data(cfg: &Config) -> Result<Dataset> {
// lengths: length of the matrix in each dimension // lengths: length of the matrix in each dimension
// returns an index if the matrix is flattened to a one dimensional vector // returns an index if the matrix is flattened to a one dimensional vector
// example for 3 dimensions N,M,O: idx = i_O + l_O*l_M*i_M + l_O*l_M*l_N*i_N // example for 3 dimensions N,M,O: idx = i_O + l_O*l_M*i_M + l_O*l_M*l_N*i_N
fn flat_index(indeces: &Vec<usize>, lengths: &Vec<usize>) -> usize { fn flat_index(indeces: &[usize], lengths: &[usize]) -> usize {
let mut idx = 0; indeces.iter().enumerate().map(|(i, idx)| {
for i in 0..indeces.len() { idx * lengths.iter().take(i).product::<usize>()
idx += indeces[i]*lengths[0..i].iter() }).sum()
.fold(1, |state, &l| { state * l });
}
idx
} }
// returns true if the values are inside the histogram boundaries defined by cfg // returns true if the values are inside the histogram boundaries defined by cfg
@@ -118,14 +115,14 @@ fn is_in_time_boundaries(time: f64, cfg: &Config) -> bool {
false false
} }
// parse a timeseries file into a histogram // parse a time series file into a histogram
fn read_window_file(window_file: &str, cfg: &Config) -> Result<Histogram> { fn read_window_file(window_file: &str, cfg: &Config) -> Result<Histogram> {
let f = File::open(window_file) let f = File::open(window_file)
.chain_err(|| format!("Failed to open sample data file {}.", window_file))?; .chain_err(|| format!("Failed to open sample data file {}.", window_file))?;
let mut buf = BufReader::new(&f); let mut buf = BufReader::new(&f);
// total number of bins is the product of all dimensions length // total number of bins is the product of all dimensions length
let total_bins = cfg.num_bins.iter().fold(1, |s, &x| { s*x }); let total_bins = cfg.num_bins.iter().product();
let mut hist = vec![0.0; total_bins]; let mut hist = vec![0.0; total_bins];
// bin width for each dimension: (max-min)/bins // bin width for each dimension: (max-min)/bins
@@ -139,7 +136,7 @@ fn read_window_file(window_file: &str, cfg: &Config) -> Result<Histogram> {
while buf.read_line(&mut line).chain_err(|| "Failed to read line")? > 0 { while buf.read_line(&mut line).chain_err(|| "Failed to read line")? > 0 {
linecount += 1; linecount += 1;
// skip comments and empty lines // skip comments and empty lines
if line.starts_with("#") || line.starts_with("@") || line.len() == 0 { if line.starts_with('#') || line.starts_with('@') || line.is_empty() {
line.clear(); line.clear();
continue; continue;
} }
@@ -158,7 +155,7 @@ fn read_window_file(window_file: &str, cfg: &Config) -> Result<Histogram> {
} }
if is_in_hist_boundaries(&values[1..], cfg) && is_in_time_boundaries(values[0], cfg) { if is_in_hist_boundaries(&values[1..], cfg) && is_in_time_boundaries(values[0], cfg) {
let bin_indeces = (0..cfg.dimens).map(|dimen: usize| { let bin_indeces: Vec<usize> = (0..cfg.dimens).map(|dimen: usize| {
let val = values[dimen+1]; let val = values[dimen+1];
((val - cfg.hist_min[dimen]) / bin_width[dimen]) as usize ((val - cfg.hist_min[dimen]) / bin_width[dimen]) as usize
}).collect(); }).collect();
@@ -174,20 +171,22 @@ fn read_window_file(window_file: &str, cfg: &Config) -> Result<Histogram> {
} }
// Write WHAM calculation results to out_file. // Write WHAM calculation results to out_file.
pub fn write_results(out_file: &str, ds: &Dataset, free: &Vec<f64>, free_std: &Vec<f64>, prob: &Vec<f64>, prob_std: &Vec<f64>) -> Result<()> { pub fn write_results(out_file: &str, ds: &Dataset, free: &[f64],
free_std: &[f64], prob: &[f64], prob_std: &[f64]) -> Result<()> {
let output = File::create(out_file) let output = File::create(out_file)
.chain_err(|| format!("Failed to create file with path {}", out_file))?; .chain_err(|| format!("Failed to create file with path {}", out_file))?;
let mut buf = BufWriter::new(output); let mut buf = BufWriter::new(output);
let header: String = (0..ds.dimens_lengths.len()).map(|d| format!("coord{}", d+1)) let header: String = (0..ds.dimens_lengths.len()).map(|d| format!("coord{}", d+1))
.collect::<Vec<String>>().join(" "); .collect::<Vec<String>>().join(" ");
writeln!(buf, "#{} {} {} {} {}", header, "Free Energy", "+/-", "Probability", "+/-"); writeln!(buf, "#{} Free Energy +/- Probability +/-", header).unwrap();
for bin in 0..free.len() { for bin in 0..free.len() {
let coords = ds.get_coords_for_bin(bin); let coords = ds.get_coords_for_bin(bin);
let coords_str: String = coords.iter().map(|c| {format!("{:8.6} ", c)}) let coords_str: String = coords.iter().map(|c| {format!("{:8.6} ", c)})
.collect::<Vec<String>>().join("\t"); .collect::<Vec<String>>().join("\t");
writeln!(buf, "{}{:8.6} {:8.6} {:8.6} {:8.6}", coords_str, free[bin], free_std[bin], prob[bin], prob_std[bin]) writeln!(buf, "{}{:8.6} {:8.6} {:8.6} {:8.6}", coords_str,
free[bin], free_std[bin], prob[bin], prob_std[bin])
.chain_err(|| "Failed to write to file.")?; .chain_err(|| "Failed to write to file.")?;
} }
Ok(()) Ok(())
@@ -196,10 +195,12 @@ pub fn write_results(out_file: &str, ds: &Dataset, free: &Vec<f64>, free_std: &V
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use assert_approx_eq::assert_approx_eq;
fn cfg() -> Config { fn cfg() -> Config {
Config { Config {
metadata_file: "example/1d_cyclic/metadata.dat".to_string(), metadata_file: "example/1d_cyclic/metadata.dat".to_string(),
hist_min: vec![-3.14], hist_min: vec![-3.14],
hist_max: vec![3.14], hist_max: vec![3.14],
num_bins: vec![10], num_bins: vec![10],
@@ -224,12 +225,12 @@ mod tests {
let h = super::read_window_file(&f, &cfg).unwrap(); let h = super::read_window_file(&f, &cfg).unwrap();
println!("{:?}", h); println!("{:?}", h);
assert_eq!(5000, h.num_points); assert_eq!(5000, h.num_points);
assert_eq!(0.0, h.bins[2]); assert_approx_eq!(0.0, h.bins[2]);
assert_eq!(11.0, h.bins[3]); assert_approx_eq!(11.0, h.bins[3]);
assert_eq!(2236.0, h.bins[4]); assert_approx_eq!(2236.0, h.bins[4]);
assert_eq!(2714.0, h.bins[5]); assert_approx_eq!(2714.0, h.bins[5]);
assert_eq!(39.0, h.bins[6]); assert_approx_eq!(39.0, h.bins[6]);
assert_eq!(0.0, h.bins[7]); assert_approx_eq!(0.0, h.bins[7]);
} }
@@ -241,7 +242,7 @@ mod tests {
assert_eq!(25, ds.num_windows); assert_eq!(25, ds.num_windows);
assert_eq!(cfg.num_bins.len(), ds.dimens_lengths.len()); assert_eq!(cfg.num_bins.len(), ds.dimens_lengths.len());
assert_eq!(cfg.num_bins[0], ds.dimens_lengths[0]); assert_eq!(cfg.num_bins[0], ds.dimens_lengths[0]);
assert_eq!(cfg.temperature * k_B, ds.kT); assert_approx_eq!(cfg.temperature * k_B, ds.kT);
assert_eq!(25, ds.histograms.len()) assert_eq!(25, ds.histograms.len())
} }

View File

@@ -5,6 +5,10 @@ extern crate error_chain;
extern crate rand; extern crate rand;
extern crate rgsl; extern crate rgsl;
extern crate rayon; extern crate rayon;
#[cfg(test)]
#[macro_use]
extern crate assert_approx_eq;
pub mod io; pub mod io;
pub mod histogram; pub mod histogram;
@@ -21,7 +25,7 @@ pub mod errors { error_chain!{} }
use errors::*; use errors::*;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
static k_B: f64 = 0.0083144621; // kJ/mol*K static k_B: f64 = 0.008_314_462_1; // kJ/mol*K
// Application config // Application config
#[derive(Debug)] #[derive(Debug)]
@@ -45,7 +49,9 @@ pub struct Config {
impl fmt::Display for Config { impl fmt::Display for Config {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Metadata={}, hist_min={:?}, hist_max={:?}, bins={:?} verbose={}, tolerance={}, iterations={}, temperature={}, cyclic={:?}, bootstrap={:?}, seed={:?}", write!(f, "Metadata={}, hist_min={:?}, hist_max={:?}, bins={:?},
verbose={}, tolerance={}, iterations={}, temperature={},
cyclic={:?}, bootstrap={:?}, seed={:?}",
self.metadata_file, self.hist_min, self.hist_max, self.num_bins, self.metadata_file, self.hist_min, self.hist_max, self.num_bins,
self.verbose, self.tolerance, self.max_iterations, self.temperature, self.verbose, self.tolerance, self.max_iterations, self.temperature,
self.cyclic, self.bootstrap, self.bootstrap_seed) self.cyclic, self.bootstrap, self.bootstrap_seed)
@@ -56,25 +62,34 @@ impl fmt::Display for Config {
// converged if the maximal difference for the calculated bias offsets is // converged if the maximal difference for the calculated bias offsets is
// smaller then a tolerance value. // smaller then a tolerance value.
fn is_converged(old_F: &[f64], new_F: &[f64], tolerance: f64) -> bool { fn is_converged(old_F: &[f64], new_F: &[f64], tolerance: f64) -> bool {
!new_F.iter().zip(old_F.iter()) // calculates abs diff between every old and new F and checks if any
.map(|x| { (x.0-x.1).abs() }) // is larger than tolerance
.any(|diff| { diff > tolerance }) !new_F.iter()
.zip(old_F.iter())
.map(|x| { (x.0-x.1).abs() })
.any(|diff| { diff > tolerance })
} }
// estimate the probability of a bin of the histogram set based on given bias offsets (F) // estimate the probability of a bin of the histogram set based on given bias
// This evaluates the first WHAM equation for each bin. // offsets (F). This evaluates the first WHAM equation for each bin:
// P(x) = \frac {\sum_{i=1}^N{n_i(x)}}
// {\sum_{i=1}^N{ N_i exp(\beta [F_i - U_{bias,i}(x)])}}
fn calc_bin_probability(bin: usize, dataset: &Dataset, F: &[f64]) -> f64 { fn calc_bin_probability(bin: usize, dataset: &Dataset, F: &[f64]) -> f64 {
let mut denom_sum: f64 = 0.0; let mut denom_sum: f64 = 0.0;
let bin_count: f64 = dataset.get_weighted_bin_count(bin); let bin_count: f64 = dataset.get_weighted_bin_count(bin);
for (window, h) in dataset.histograms.iter().enumerate() { for (window, h) in dataset.histograms.iter().enumerate() {
let bias = dataset.get_bias(bin, window); let bias = dataset.get_bias(bin, window);
denom_sum += (dataset.weights[window] * h.num_points as f64) * bias * F[window]; denom_sum += (dataset.weights[window] * h.num_points as f64)
* bias * F[window];
} }
bin_count / denom_sum bin_count / denom_sum
} }
// estimate the bias offset F of the histogram based on given probabilities. // estimate the bias offset F of the histogram based on given probabilities.
// This evaluates the second WHAM equation for each window and returns exp(F/kT) // This evaluates the second WHAM equation for each window and returns exp(F/kT).
// exp(F/kT) is not required in intermediate steps so we save some time by not
// calculating it for every iteration.
// F_i = - 1/\beta ln[\sum_{X_{bins}}{P(x)exp(-\beta U_{bias,i}(x))}]
fn calc_window_F(window: usize, dataset: &Dataset, P: &[f64]) -> f64 { fn calc_window_F(window: usize, dataset: &Dataset, P: &[f64]) -> f64 {
let f: f64 = (0..dataset.num_bins).zip(P.iter()) // zip bins and P let f: f64 = (0..dataset.num_bins).zip(P.iter()) // zip bins and P
.map(|bin_and_prob: (usize, &f64)| { .map(|bin_and_prob: (usize, &f64)| {
@@ -84,16 +99,18 @@ fn calc_window_F(window: usize, dataset: &Dataset, P: &[f64]) -> f64 {
1.0/f 1.0/f
} }
// One full WHAM iteration includes calculation of new probabilities P and // One full WHAM iteration: calculation of new probabilities P and new bias
// new bias offsets F based on previous bias offsets F_prev. This updates // offsets F based on previous bias offsets F_prev. This updates the values in
// the values in vectors F and P // vectors F and P.
fn perform_wham_iteration(dataset: &Dataset, F_prev: &[f64], F: &mut Vec<f64>, P: &mut Vec<f64>) { fn perform_wham_iteration(dataset: &Dataset, F_prev: &[f64], F: &mut Vec<f64>, P: &mut Vec<f64>) {
// evaluate first WHAM equation for each bin to // Update P
// estimage probabilities based on previous offsets (F_prev)) // evaluate first WHAM equation for each bin to
(0..dataset.num_bins).into_par_iter() // estimate probabilities based on previous offsets (F_prev))
(0..dataset.num_bins).into_par_iter()
.map(|bin| { calc_bin_probability(bin, dataset, F_prev) }) .map(|bin| { calc_bin_probability(bin, dataset, F_prev) })
.collect_into_vec(P); .collect_into_vec(P);
// Update F
// evaluate second WHAM equation for each window to // evaluate second WHAM equation for each window to
// estimate new bias offsets from propabilities // estimate new bias offsets from propabilities
(0..dataset.num_windows).into_par_iter() (0..dataset.num_windows).into_par_iter()
@@ -101,12 +118,20 @@ fn perform_wham_iteration(dataset: &Dataset, F_prev: &[f64], F: &mut Vec<f64>, P
.collect_into_vec(F); .collect_into_vec(F);
} }
pub fn perform_wham(cfg: &Config, dataset: &Dataset) -> Result<(Vec<f64>, Vec<f64>, Vec<f64>)> { // Full WHAM calculation. Calls `perform_wham_iteration` until convergence
// criteria are met or max iterations reached.
pub fn perform_wham(cfg: &Config, dataset: &Dataset)
-> Result<(Vec<f64>, Vec<f64>, Vec<f64>)> {
// allocate required vectors. // allocate required vectors.
let mut P: Vec<f64> = vec![f64::NAN; dataset.num_bins]; // bin probability
let mut F: Vec<f64> = vec![1.0; dataset.num_windows]; // bias offset exp(F/kT) // bin probability
let mut F_prev: Vec<f64> = vec![f64::NAN; dataset.num_windows]; // previous bias offset let mut P: Vec<f64> = vec![f64::NAN; dataset.num_bins];
let mut F_tmp: Vec<f64> = vec![f64::NAN; dataset.num_windows]; // temp storage for F // bias offset exp(F/kT)
let mut F: Vec<f64> = vec![1.0; dataset.num_windows];
// previous bias offset
let mut F_prev: Vec<f64> = vec![f64::NAN; dataset.num_windows];
// temp storage for F
let mut F_tmp: Vec<f64> = vec![f64::NAN; dataset.num_windows];
let mut iteration = 0; let mut iteration = 0;
let mut converged = false; let mut converged = false;
@@ -118,33 +143,32 @@ pub fn perform_wham(cfg: &Config, dataset: &Dataset) -> Result<(Vec<f64>, Vec<f6
// store F values before the next iteration // store F values before the next iteration
F_prev.copy_from_slice(&F); F_prev.copy_from_slice(&F);
// perform wham iteration (this updates F and P) // perform wham iteration (this updates F and P).
perform_wham_iteration(&dataset, &F_prev, &mut F, &mut P); perform_wham_iteration(&dataset, &F_prev, &mut F, &mut P);
// convergence check // convergence check
if iteration % 10 == 0 { if iteration % 10 == 0 {
// This backups exp(F/kT) in a temporary vector and calculates true F and F_prev for // This backups exp(F/kT) in a temporary vector and calculates
// convergence. Finally, F is restored. F_prev does not need to be restored because // true F and F_prev for convergence. Finally, F is restored.
// its overwritten for the next iteration. // F_prev does not need to be restored because its overwritten
// for the next iteration.
F_tmp.copy_from_slice(&F); F_tmp.copy_from_slice(&F);
for f in F.iter_mut() { *f = -dataset.kT * f.ln() } for f in F.iter_mut() { *f = -dataset.kT * f.ln() }
for f in F_prev.iter_mut() { *f = -dataset.kT * f.ln() } for f in F_prev.iter_mut() { *f = -dataset.kT * f.ln() }
converged = is_converged(&F_prev, &F, cfg.tolerance); converged = is_converged(&F_prev, &F, cfg.tolerance);
println!("Iteration {}: dF={}", &iteration, &diff_avg(&F_prev, &F)); if cfg.verbose {
println!("Iteration {}: dF={}", &iteration, &diff_avg(&F_prev, &F));
}
F.copy_from_slice(&F_tmp); F.copy_from_slice(&F_tmp);
} }
// Dump free energy and bias offsets
//if iteration % 100 == 0 {
// free_energy(&histograms, &mut P, &mut A);
// dump_state(&histograms, &F, &F_prev, &P, &A);
//}
} }
// Normalize P to sum(P) = 1.0 // Normalize P to sum(P) = 1.0
let P_sum: f64 = P.iter().sum(); let P_sum: f64 = P.iter().sum();
P.iter_mut().map(|p| *p /= P_sum).count(); for p in P.iter_mut() {
*p /= P_sum;
}
if iteration == cfg.max_iterations { if iteration == cfg.max_iterations {
bail!("WHAM not converged! (max iterations reached)"); bail!("WHAM not converged! (max iterations reached)");
@@ -161,17 +185,14 @@ pub fn run(cfg: &Config) -> Result<()>{
println!("{}", &dataset); println!("{}", &dataset);
let (P, F, F_prev) = perform_wham(&cfg, &dataset)?; let (P, F, F_prev) = perform_wham(&cfg, &dataset)?;
println!("WHAM converged.");
let P_std: Vec<f64>; let (P_std, free_energy_std) = if cfg.bootstrap > 0 {
let free_energy_std: Vec<f64>; println!("Bootstrapping..");
if cfg.bootstrap > 0 { error_analysis::run_bootstrap(&cfg, dataset.clone(), cfg.bootstrap)
let error_est = error_analysis::run_bootstrap(&cfg, dataset.clone(), &P, cfg.bootstrap);
P_std = error_est.0;
free_energy_std = error_est.1;
} else { } else {
P_std = vec![0.0; P.len()]; (vec![0.0; P.len()], vec![0.0; P.len()])
free_energy_std = vec![0.0; P.len()]; };
}
// calculate free energy and dump state // calculate free energy and dump state
println!("Finished. Dumping final PMF"); println!("Finished. Dumping final PMF");
@@ -214,19 +235,23 @@ fn calc_free_energy(dataset: &Dataset, P: &[f64]) -> Vec<f64> {
free_energy free_energy
} }
fn dump_state(dataset: &Dataset, F: &[f64], F_prev: &[f64], P: &[f64], P_std: &[f64], A: &[f64], A_std: &[f64]) { // Print the current WHAM iteration state. Dumps the PMF and associated vectors
fn dump_state(dataset: &Dataset, F: &[f64], F_prev: &[f64], P: &[f64],
P_std: &[f64], A: &[f64], A_std: &[f64]) {
// TODO fix output of F/F_prev // TODO fix output of F/F_prev
let out = std::io::stdout(); let out = std::io::stdout();
let mut lock = out.lock(); let mut lock = out.lock();
writeln!(lock, "# PMF"); writeln!(lock, "# PMF").unwrap();
writeln!(lock, "#bin\t\tFree Energy\t\t+/-\t\tP(x)\t\t+/-"); writeln!(lock, "#bin\t\tFree Energy\t\t+/-\t\tP(x)\t\t+/-").unwrap();
for bin in 0..dataset.num_bins { for bin in 0..dataset.num_bins {
writeln!(lock, "{:9.5}\t{:9.5}\t{:9.5}\t{:9.5}\t{:9.5}", bin, A[bin], A_std[bin], P[bin], P_std[bin]); writeln!(lock, "{:9.5}\t{:9.5}\t{:9.5}\t{:9.5}\t{:9.5}",
bin, A[bin], A_std[bin], P[bin], P_std[bin]).unwrap();
} }
writeln!(lock, "# Bias offsets"); writeln!(lock, "# Bias offsets").unwrap();
writeln!(lock, "#Window\t\tF\t\tF_prev"); writeln!(lock, "#Window\t\tF\t\tF_prev").unwrap();
for window in 0..dataset.num_windows { for window in 0..dataset.num_windows {
writeln!(lock, "{}\t{:9.5}\t{:8.8}", window, F[window], (F[window]-F_prev[window]).abs()); writeln!(lock, "{}\t{:9.5}\t{:8.8}",
window, F[window], (F[window]-F_prev[window]).abs()).unwrap();
} }
} }
@@ -268,23 +293,23 @@ mod tests {
fn calc_bin_probability() { fn calc_bin_probability() {
let dataset = create_test_dataset(); let dataset = create_test_dataset();
let F = vec![1.0; dataset.num_bins] ; let F = vec![1.0; dataset.num_bins] ;
let expected = vec!(0.0, 0.0825296687031316, 40.92355847097493, let expected = vec!(0.0, 0.082_529_668_703_131_6, 40.923_558_470_974_93,
124226.70003377, 2308526035.5283747); 124_226.700_033_77, 2_308_526_035.528_374_7);
for b in 0..dataset.num_bins { expected.iter().enumerate().for_each(|(i, exp)| {
let p = super::calc_bin_probability(b, &dataset, &F); let p = super::calc_bin_probability(i, &dataset, &F);
assert_delta!(expected[b], p, 0.0000001); assert_delta!(exp, p, 0.000_000_1);
} })
} }
#[test] #[test]
fn calc_bias_offset() { fn calc_bias_offset() {
let dataset = create_test_dataset(); let dataset = create_test_dataset();
let probability = vec!(0.0, 0.1, 0.2, 0.3, 0.4); let probability = vec!(0.0, 0.1, 0.2, 0.3, 0.4);
let expected = vec!(15.927477169990633, 15.927477169990633); let expected = vec!(15.927_477_169_990_633, 15.927_477_169_990_633);
for window in 0..dataset.num_windows { expected.iter().enumerate().for_each(|(i, exp)| {
let F = super::calc_window_F(window, &dataset, &probability); let F = super::calc_window_F(i, &dataset, &probability);
assert_delta!(expected[window], F, 0.0000001); assert_delta!(exp, F, 0.000_000_1);
} })
} }
#[test] #[test]
@@ -295,8 +320,8 @@ mod tests {
let mut P = vec![f64::NAN; dataset.num_bins]; let mut P = vec![f64::NAN; dataset.num_bins];
super::perform_wham_iteration(&dataset, &prev_F, &mut F, &mut P); super::perform_wham_iteration(&dataset, &prev_F, &mut F, &mut P);
let expected_F = vec!(1.0, 1.0); let expected_F = vec!(1.0, 1.0);
let expected_P = vec!(0.0, 0.0825296687031316, 40.92355847097493, let expected_P = vec!(0.0, 0.082_529_668_703_131_6, 40.923_558_470_974_93,
124226.70003377, 2308526035.5283747); 124_226.700_033_77, 2_308_526_035.528_374_7);
for bin in 0..dataset.num_bins { for bin in 0..dataset.num_bins {
assert_delta!(expected_P[bin], P[bin], 0.01) assert_delta!(expected_P[bin], P[bin], 0.01)
} }

View File

@@ -2,8 +2,6 @@ mod command;
#[cfg(test)] #[cfg(test)]
mod integration { mod integration {
use std::process::Command;
use super::command::get_command; use super::command::get_command;
#[test] #[test]