From a4b6e7d145f11a2bba1e539dc982d4f5a8ea3ff2 Mon Sep 17 00:00:00 2001 From: bussilabbot Date: Thu, 17 Oct 2024 15:40:29 +0000 Subject: [PATCH] Update to bussilab/py-bussilab@191f1c7 --- .nojekyll | 0 README.md | 13 + bussilab.pdf | Bin 0 -> 148929 bytes bussilab/ann.html | 559 ++ bussilab/cli.html | 200 + bussilab/cli_documentation.html | 325 + bussilab/clustering.html | 227 + bussilab/coretools.html | 358 ++ bussilab/cron.html | 69 + bussilab/index.html | 440 ++ bussilab/jremote.html | 91 + bussilab/lohman.html | 94 + bussilab/maxent.html | 236 + bussilab/notify.html | 180 + bussilab/pip.html | 102 + bussilab/potts.html | 351 + bussilab/reports.html | 69 + bussilab/wham.html | 277 + examples/MaxEnt.html | 7865 +++++++++++++++++++++++ examples/example_ann.html | 10214 ++++++++++++++++++++++++++++++ examples/example_lohman.html | 7639 ++++++++++++++++++++++ examples/example_potts.html | 7725 ++++++++++++++++++++++ examples/index.html | 42 + index.html | 10 + 24 files changed, 37086 insertions(+) create mode 100644 .nojekyll create mode 100644 README.md create mode 100644 bussilab.pdf create mode 100644 bussilab/ann.html create mode 100644 bussilab/cli.html create mode 100644 bussilab/cli_documentation.html create mode 100644 bussilab/clustering.html create mode 100644 bussilab/coretools.html create mode 100644 bussilab/cron.html create mode 100644 bussilab/index.html create mode 100644 bussilab/jremote.html create mode 100644 bussilab/lohman.html create mode 100644 bussilab/maxent.html create mode 100644 bussilab/notify.html create mode 100644 bussilab/pip.html create mode 100644 bussilab/potts.html create mode 100644 bussilab/reports.html create mode 100644 bussilab/wham.html create mode 100644 examples/MaxEnt.html create mode 100644 examples/example_ann.html create mode 100644 examples/example_lohman.html create mode 100644 examples/example_potts.html create mode 100644 examples/index.html create mode 100644 index.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5cf6a84 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +Precompiled manual for py-bussilab +------------------------------- + +This repository hosts a precompiled manual for py-bussilab +git revision [191f1c7](https://github.com/bussilab/py-bussilab/commit/191f1c7). + +To browse the manual you should go [here](http://bussilab.github.io/doc-py-bussilab). + +You can also download a full copy of the manual for offline access +at [this link](http://github.com/bussilab/doc-py-bussilab/archive/master.zip). + +This manual has been compiled on [GitHub Actions](https://github.com/bussilab/py-bussilab/actions) on Thu Oct 17 15:40:29 UTC 2024. + diff --git a/bussilab.pdf b/bussilab.pdf new file mode 100644 index 0000000000000000000000000000000000000000..00e3d72bcc5a8b9ee252ccce3b17c63aefee9609 GIT binary patch literal 148929 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 + + + + + +bussilab.ann API documentation + + + + + + + + + + + +

+
+
+

Module bussilab.ann

+
+
+

Module with artificial neural networks.

+

ANN can be constructed with cuda=True, in which case it will use cudamat.

+
+
+
+
+
+
+
+
+

Classes

+
+
+class ANN +(layers, random_weights=False, init_b=0.0, activation='softplus', cuda=False) +
+
+
+
+ +Expand source code + +
class ANN:
+    # constructor, allocate space for parameters
+    def __init__(self,layers,random_weights=False,init_b=0.0,activation="softplus",cuda=False):
+
+        if cuda is None:
+            cuda = _HAS_CUDAMAT
+
+        if cuda:
+            _ensure_cm_init()
+
+        self.cuda=cuda
+
+        if not self.cuda:
+            if activation == 'softplus':
+                self._activation=_softplus
+                self._dactivation=_sigmoid
+            elif activation == 'relu':
+                self._activation=_relu
+                self._dactivation=_drelu
+            else:
+                raise ValueError("Unknown activation type: "+activation)
+        else:
+            if not _HAS_CUDAMAT:
+                raise ValueError("Cudamat not available, can only run ANN with numpy")
+            if activation == 'softplus':
+                self._cu_activation=cm.log_1_plus_exp
+                self._cu_dactivation=_sigmoid_cudamat
+            elif activation == 'relu':
+                self._cu_activation=_relu_cudamat
+                self._cu_dactivation=_drelu_cudamat
+            else:
+                raise ValueError("Unknown activation type: "+activation)
+        self.activation=activation
+        self.layers=layers
+        self.W=[]
+        self.b=[]
+        for i in range(len(self.layers)-1):
+            self.W.append(np.zeros(shape=(self.layers[i],self.layers[i+1])))
+            self.b.append(np.zeros(shape=(self.layers[i+1]))+init_b)
+        self.W.append(np.zeros(shape=(self.layers[len(layers)-1],1)))
+        self.b.append(np.zeros(shape=(1))+init_b)
+
+        n=0
+        for i in range(len(self.W)):
+            n+=np.prod(self.W[i].shape)
+        self.nparW=n
+
+        n=0
+        for i in range(len(self.b)):
+            n+=np.prod(self.b[i].shape)
+        self.nparB=n
+
+        self.npar=self.nparW + self.nparB
+
+        self.narg=self.layers[0]
+
+        if random_weights:
+            # see Deep Learning, Eq. 8.23
+            for i in range(len(self.W)):
+                self.W[i]+=np.random.uniform(-1.0,1.0,size=self.W[i].shape)*np.sqrt(6/(np.sum(self.W[i].shape)))
+        if self.cuda:
+            self.cuda_setup()
+
+    def cuda_setup(self):
+        self.cu_W=[]
+        for i in range(len(self.W)):
+            self.cu_W.append(cm.CUDAMatrix(self.W[i]))
+        self.cu_b=[]
+        for i in range(len(self.b)):
+            self.cu_b.append(cm.CUDAMatrix(np.reshape(self.b[i],(1,-1))))
+
+    # set array of parameters
+    def setpar(self,par):
+        assert len(par)==self.npar
+        n=0
+        for i in range(len(self.W)):
+            self.W[i]=np.reshape(par[n:n+np.prod(self.W[i].shape)],self.W[i].shape)
+            n+=np.prod(self.W[i].shape)
+        for i in range(len(self.b)):
+            self.b[i]=np.reshape(par[n:n+np.prod(self.b[i].shape)],self.b[i].shape)
+            n+=np.prod(self.b[i].shape)
+        if self.cuda:
+            self.cuda_setup()
+        return self
+
+    def getpar(self):
+        par=np.zeros(self.npar)
+        n=0
+        for i in range(len(self.W)):
+            m=np.prod(self.W[i].shape)
+            par[n:n+m]=self.W[i].flatten()
+            n+=m
+        for i in range(len(self.b)):
+            m=np.prod(self.b[i].shape)
+            par[n:n+m]=self.b[i]
+            n+=m
+        return par
+
+    # compute function and derivative wrt flatten parameters for a vector of samples
+    def derpar(self,x):
+        x = ensure_np_array(x)
+
+        if len(x.shape)==1:
+            f, der = self.derpar(x.reshape((-1,len(x))))
+            return f[0], der[0]
+        elif len(x.shape)>2:
+            raise TypeError("Incorrectly shaped x")
+
+        assert x.shape[1]==self.narg
+        f,df_dW,df_db=self.deriv(x)
+        der=np.zeros((x.shape[0],self.npar),dtype=f.dtype)
+        n=0
+        for i in range(len(self.W)):
+            m=np.prod(self.W[i].shape)
+            der[:,n:n+m]=df_dW[i].reshape(x.shape[0],-1)
+            n+=m
+        for i in range(len(self.b)):
+            m=np.prod(self.b[i].shape)
+            der[:,n:n+m]=df_db[i].reshape(x.shape[0],-1)
+            n+=m
+        return f,der
+
+    # evaluate the NN on a single point or on an array of points
+    def apply(self,x):
+        x = ensure_np_array(x)
+        if len(x.shape)==1:
+            return self.apply(x.reshape((1,len(x))))[0]
+        elif len(x.shape)>2:
+            raise TypeError("Incorrectly shaped x")
+        assert x.shape[1]==self.narg
+
+        if not self.cuda:
+            for i in range(len(self.W)):
+                x=np.matmul(x,self.W[i])+self.b[i]
+                if i+1<len(self.W):
+                    x = self._activation(x)
+        else:
+            cu_x=cm.CUDAMatrix(x)
+            for i in range(len(self.cu_W)):
+                cu_x=cm.dot(cu_x,self.cu_W[i])
+                cu_x.add_row_vec(self.cu_b[i])
+                if i+1<len(self.cu_W):
+                    self._cu_activation(cu_x)
+            x=np.array(cu_x.asarray())
+
+        return x[:,0]
+
+
+    def forward(self,x):
+        x = ensure_np_array(x)
+
+        if len(x.shape)==1:
+            f,df_dW,df_db = self.deriv(x.reshape((1,len(x))))
+            for i in range(len(df_dW)):
+                df_dW[i]=df_dW[i][0]
+                df_db[i]=df_db[i][0]
+            return f[0], df_dW, df_db
+        elif len(x.shape)>2:
+            raise TypeError("Incorrectly shaped x")
+
+        # allocate hidden nodes
+        h=[None]*len(self.layers)  # hidden nodes
+        ht=[None]*len(self.layers)  # non-linear functions of hidden nodes
+
+        if not self.cuda:
+            # forward propagation
+            ht[0]=x.copy()
+            for i in range(len(self.layers)-1):
+                h[i+1]=np.matmul(ht[i],self.W[i])+self.b[i]
+                ht[i+1] = self._activation(h[i+1])
+            f=(np.matmul(ht[-1],self.W[-1])+self.b[-1])[:,0]
+        else:
+            ht[0]=cm.CUDAMatrix(x)
+            for i in range(len(self.cu_W)-1):
+                h[i+1]=cm.dot(ht[i],self.cu_W[i])
+                h[i+1].add_row_vec(self.cu_b[i])
+                ht[i+1]=h[i+1].copy()
+                self._cu_activation(ht[i+1])
+            f=cm.dot(ht[-1],self.cu_W[-1])
+            f.add_row_vec(self.cu_b[-1])
+
+        class State(coretools.Result):
+            pass
+        return State(f=f,h=h,ht=ht)
+
+    def backward(self,deriv,hidden):
+        # allocate derivatives
+        df_dW=[None]*len(self.layers)
+        df_db=[None]*len(self.layers)
+
+        if not self.cuda:
+            df_db[-1]=np.ones((len(hidden.f),1))
+            df_dW[-1]=np.matmul(deriv,hidden.ht[-1])[:,np.newaxis]
+            for i in reversed(range(len(self.layers)-1)):
+                df_db[i]=np.matmul(df_db[i+1],self.W[i+1].T) * self._dactivation(hidden.h[i+1])
+                df_dW[i]=np.einsum("i,ij,ik->jk",deriv,hidden.ht[i],df_db[i])
+            for i in range(len(self.layers)):
+                df_db[i]=np.matmul(deriv,df_db[i])
+
+        else:
+            if not isinstance(deriv,cm.CUDAMatrix):
+                deriv=deriv.reshape((1,-1))
+                deriv=cm.CUDAMatrix(deriv)
+
+            if deriv.shape[1]==1:
+                deriv=deriv.transpose()
+
+            vec=deriv.shape[1]
+
+            df_db[-1]=cm.CUDAMatrix(np.ones((vec,1)))
+            df_dW[-1]=cm.dot(deriv,hidden.ht[-1]).transpose()
+
+            for i in reversed(range(len(self.layers)-1)):
+                self._cu_dactivation(hidden.h[i+1])
+                df_db[i]=cm.dot(df_db[i+1],self.cu_W[i+1].transpose())
+                df_db[i].mult(hidden.h[i+1])
+
+                hidden.ht[i].mult_by_col(deriv.transpose())
+                df_dW[i]=cm.dot(hidden.ht[i].transpose(),df_db[i])
+
+            for i in range(len(self.layers)):
+                df_db[i]=cm.dot(deriv,df_db[i])
+            for i in range(len(df_db)):
+                df_db[i]=df_db[i].asarray()[0,:]
+            for i in range(len(df_db)):
+                df_dW[i]=df_dW[i].asarray()
+
+        return df_dW,df_db
+
+    def backward_par(self,deriv,hidden):
+        df_dW,df_db=self.backward(deriv,hidden)
+        if not self.cuda:
+            der=np.zeros(self.npar,dtype=hidden.f.dtype)
+        else:
+            der=np.zeros(self.npar,dtype=df_dW[0].dtype)
+        n=0
+        for i in range(len(self.W)):
+            m=np.prod(self.W[i].shape)
+            der[n:n+m]=df_dW[i].flatten()
+            n+=m
+        for i in range(len(self.b)):
+            m=np.prod(self.b[i].shape)
+            der[n:n+m]=df_db[i]
+            n+=m
+        assert(n==self.npar)
+        return der
+
+
+    # compute derivatives with respect to parameters
+    def deriv(self,x):
+
+        x = ensure_np_array(x)
+
+        if len(x.shape)==1:
+            f,df_dW,df_db = self.deriv(x.reshape((1,len(x))))
+            for i in range(len(df_dW)):
+                df_dW[i]=df_dW[i][0]
+                df_db[i]=df_db[i][0]
+            return f[0], df_dW, df_db
+        elif len(x.shape)>2:
+            raise TypeError("Incorrectly shaped x")
+
+        assert x.shape[1]==self.narg
+
+        vec=x.shape[0]
+
+        # allocate hidden nodes
+        h=[None]*len(self.layers)  # hidden nodes
+        ht=[None]*len(self.layers)  # non-linear functions of hidden nodes
+
+        # allocate derivatives
+        df_dW=[None]*len(self.layers)
+        df_db=[None]*len(self.layers)
+
+        if not self.cuda:
+
+            # forward propagation
+            ht[0]=x.copy()
+
+            for i in range(len(self.layers)-1):
+                h[i+1]=np.matmul(ht[i],self.W[i])+self.b[i]
+                ht[i+1] = self._activation(h[i+1])
+
+            f=(np.matmul(ht[-1],self.W[-1])+self.b[-1])[:,0]
+
+            # backward propagation
+
+            df_db[-1]=np.ones((vec,1))
+            df_dW[-1]=ht[-1][:,:,np.newaxis]
+
+            for i in reversed(range(len(self.layers)-1)):
+                df_db[i]=np.matmul(df_db[i+1],self.W[i+1].T) * self._dactivation(h[i+1])
+                df_dW[i]=ht[i][:,:,np.newaxis]*df_db[i][:,np.newaxis,:]
+
+        else:
+
+            # forward propagation
+            ht[0]=cm.CUDAMatrix(x)
+
+            for i in range(len(self.cu_W)-1):
+                h[i+1]=cm.dot(ht[i],self.cu_W[i])
+                h[i+1].add_row_vec(self.cu_b[i])
+                ht[i+1]=h[i+1].copy()
+                self._cu_activation(ht[i+1])
+
+            f=cm.dot(ht[-1],self.cu_W[-1]).asarray()[:,0]+self.b[-1][0]
+
+            # backward propagation
+
+            df_db_host=[None]*len(self.layers)
+
+            df_db[-1]=cm.CUDAMatrix(np.ones((vec,1)))
+            df_dW[-1]=ht[-1].asarray()[:,:,np.newaxis]
+
+            df_db_host[-1]=df_db[-1].asarray()
+
+            for i in reversed(range(len(self.layers)-1)):
+                self._cu_dactivation(h[i+1])
+                df_db[i]=cm.dot(df_db[i+1],self.cu_W[i+1].transpose())
+                df_db[i].mult(h[i+1])
+                df_db_host[i]=df_db[i].asarray()  # should be moved to CPU anyway
+ 
+                # this is still on CPU, but could be done on GPU avoiding the movement of ht[i]
+                df_dW[i]=ht[i].asarray()[:,:,np.newaxis]*df_db_host[i][:,np.newaxis,:]
+
+            df_db=df_db_host
+
+            f=np.array(f)
+
+        return f,df_dW,df_db
+
+    # these are aliases for backward compatibility
+    def applyVec(self,x):
+        return self.apply(x)
+    def derivVec(self,x):
+        return self.deriv(x)
+    def derparVec(self,x):
+        return self.derpar(x)
+
+    def dumpPlumed(self,path,style="ann",prefix=None,arguments=None):
+        if style == "ann":
+            with open(path,"w") as f:
+                for i in range(len(self.W)):
+                    ni=self.W[i].shape[0]
+                    no=self.W[i].shape[1]
+                    print("#! FIELDS "+" ".join(["w"+str(j) for j in range(ni)]),file=f)
+                    for j in range(no):
+                        print(' '.join(map(str, self.W[i][:,j])),file=f)
+                    print("#! FIELDS "+" ".join(["b"+str(j) for j in range(no)]),file=f)
+                    print(' '.join(map(str, self.b[i])),file=f)
+                    if i+1 < len(self.W):
+                        print("#! FIELDS "+" ".join(["activation"+str(j) for j in range(no)]),file=f)
+                        print(' '.join([self.activation]*no),file=f)
+        elif style == "combine":
+            if not prefix:
+                raise ValueError("with style combine, prefix is needed")
+            if not arguments:
+                raise ValueError("with style combine, arguments is needed")
+            with open(path,"w") as f:
+                if self.activation=="softplus":
+                    func="log(1+exp(-abs(x)))+max(x,0)"
+                else:
+                    raise ValueError("only activation softplus supported")
+                print(prefix+"_one: CONSTANT VALUE=1.0",file=f)
+                for i in range(len(self.W)):
+                    no=self.W[i].shape[1]
+                    for j in range(no):
+                        coeff=','.join(map(str, self.W[i][:,j]))
+                        coeff+=","+str(self.b[i][j])
+                        if i+1<len(self.W):
+                            result="{}_h_{}_{}".format(prefix,i,j)
+                        else:
+                            result="{}_result".format(prefix)
+                        print("{}: COMBINE ...".format(result),file=f)
+                        print("  PERIODIC=NO",file=f)
+                        print("  COEFFICIENTS={}".format(coeff),file=f)
+                        print("  ARG={},{}_one".format(arguments,prefix),file=f)
+                        print("...",file=f)
+                    if i+1<len(self.W):
+                        for j in range(no):
+                            print("{}_ht_{}_{}: CUSTOM PERIODIC=NO ARG={}_h_{}_{} FUNC={}".format(prefix,i,j,prefix,i,j,func),file=f)
+                        arguments=",".join(["{}_ht_{}_{}".format(prefix,i,j) for j in range(no)])
+        else:
+            raise ValueError("unknown style")
+
+

Methods

+
+
+def apply(self, x) +
+
+
+
+
+def applyVec(self, x) +
+
+
+
+
+def backward(self, deriv, hidden) +
+
+
+
+
+def backward_par(self, deriv, hidden) +
+
+
+
+
+def cuda_setup(self) +
+
+
+
+
+def deriv(self, x) +
+
+
+
+
+def derivVec(self, x) +
+
+
+
+
+def derpar(self, x) +
+
+
+
+
+def derparVec(self, x) +
+
+
+
+
+def dumpPlumed(self, path, style='ann', prefix=None, arguments=None) +
+
+
+
+
+def forward(self, x) +
+
+
+
+
+def getpar(self) +
+
+
+
+
+def setpar(self, par) +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/cli.html b/bussilab/cli.html new file mode 100644 index 0000000..346e655 --- /dev/null +++ b/bussilab/cli.html @@ -0,0 +1,200 @@ + + + + + + +bussilab.cli API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.cli

+
+
+

Tools to implement the command line interface

+

This module is used internally to implement the command line interface. +In addition, it can be used to run the commands that are available +in the command line interface without the need to leave python:

+
from bussilab.cli import cli
+cli("-h")
+cli("wham -b bias") # provide the command line as a string
+cli(["wham", "-b", "bias"]) # alternatively use a list
+
+

The documentation of all the commands can be found in the +cli_documentation submodule.

+

Notice however that these commands typically have alternative python +implementations that allow you to work directly on data structures +and are thus more flexible. +For instance, wham()(bias), where bias is a numpy array, +is often more convenient than bussilab.cli.cli("wham -b bias"), +where bias is a file.

+
+
+
+
+
+
+

Functions

+
+
+def arg(*name, **kwargs) +
+
+

Decorator that adds an argument to a command line tool.

+

Parameters are passed to the parser.add_argument() function. +It should be written after the command() decorator.

+
+
+def cli(arguments: Union[str, List[str]] = '', *, prog: Optional[str] = '', use_argcomplete: bool = False, throws_on_parser_errors: bool = True) ‑> Optional[int] +
+
+

Executes a command line tool from python.

+

This is the main function of this module and allows to launch all the subcommands available +in the command line interface directly from python.

+

Parameters

+
+
arguments : str or list
+
Command line arguments. If a string is passed, it is first split using +shlex.split()
+
prog : str
+
Name of the calling program. It is used to build help texts. Mostly for internal use.
+
use_argcomplete : bool
+
If True, the autocomplete function of argcomplete module is called on the parser, +so as to allow autocompletion in the command line tool. +If argcomplete module is not installed, nothing is done and no failure is reported. +Mostly for internal use.
+
throws_on_parser_errors : bool
+
If True, in case of command line error it throws a TypeError +exception. Mostly for internal use.
+
+

Returns

+
+
None or int
+
If an error happens while parsing, it throws a TypeError exception, +unless throws_on_parser_errors is set to false, in which ase it +returns the corresponding error code. +If an error happens while executing the requested command, an exception is thrown. +If everything goes well, it returns None.
+
+
+
+def command(name: str, help: Optional[str] = None, description: Optional[str] = None, **kwargs) +
+
+

Decorator that registers a function as a subcommand.

+

This decorator should be written before the other decorators +arg(), group(), and endgroup().

+

Parameters

+
+
name : str
+
Name of the subcommand (will be used on the command line)
+
help : str
+
Short help message for the subcommand (one line).
+
description : str, optional
+
Longer description. If not provided, it is set to a copy of help.
+
kwargs
+
Other parameters are passed as is to the add_parser function of argparse.
+
+

Examples

+

Simple command line tool that accepts a single --out argument followed by a string +and call the function do_something with that string as an argument.

+
from bussilab.cli import command, arg
+
+@command("subcommand")
+@arg("--out")
+def myfunc(out):
+    do_something(out)
+
+
+
+def endgroup(f: Optional[Callable] = None) +
+
+

Decorator that ends a group of arguments for a command line tool.

+

See group().

+
+
+def group(title: Union[str, Callable, ForwardRef(None)] = None, description: Optional[str] = None, exclusive: Optional[bool] = None, required: Optional[bool] = None) +
+
+

Decorator that adds a group of arguments for a command line tool.

+

It should be written after the command() decorator. +It should be followed by a number of arg() decorators and by a closing +endgroup() decorator.

+

Parameters

+
+
title : str
+
The name of the group. Can only be used for non exclusive groups.
+
description : str
+
A description of the group. Can only be used for non exclusive groups.
+
exclusive : bool
+
If True, the arguments belonging to this group are mutually exclusive
+
required : bool
+
If True, one of the arguments at least should be passed. +Can only be used for exclusive groups.
+
+

Examples

+

This is a simple command line tool that accepts three arguments (-a, -b, or -c), +mutually exclusive. When ran, it will just print booleans showing if these arguments +were passed.

+
from bussilab.cli import command, group, arg, endgroup
+
+@command("doit")
+@group(exclusive=True)
+@arg("-a", action='store_true')
+@arg("-b", action='store_true')
+@arg("-c", action='store_true')
+@endgroup
+def check(a, b, c):
+   print(a, b, c)
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/cli_documentation.html b/bussilab/cli_documentation.html new file mode 100644 index 0000000..dbd40ad --- /dev/null +++ b/bussilab/cli_documentation.html @@ -0,0 +1,325 @@ + + + + + + +bussilab.cli_documentation API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.cli_documentation

+
+
+

Documentation for command line tools

+

This module only contains the documentation of the subcommands used in the +command line interface. +For all the subcommands, a short help identical to that generated by the +-h option is shown. In addition, if present, the docstring of the +function is also shown here.

+

list

+
usage: bussilab list [-h]
+
+List available python modules.
+
+options:
+  -h, --help  show this help message and exit
+
+

check

+
usage: bussilab check [-h] [--import]
+
+Check installed features
+
+options:
+  -h, --help  show this help message and exit
+  --import    check if all the submodules can be imported
+
+

wham

+
usage: bussilab wham [-h] -b BIAS [-o OUT] [--use-frame-weight]
+                     [--traj-weight [TRAJ_WEIGHT ...]] [-T T] [-m MAXITER]
+                     [-t THRESHOLD] [-v]
+
+Perform binless WHAM
+
+options:
+  -h, --help            show this help message and exit
+  -b BIAS, --bias BIAS  File containing bias potential (default: None)
+  -o OUT, --out OUT     Output file with weights (default: None)
+  --use-frame-weight
+  --traj-weight [TRAJ_WEIGHT ...]
+  -T T, --temperature T
+                        system temperature in energy units (default: 1.0)
+  -m MAXITER, --maxiter MAXITER
+                        maximum number of iterations (default: 1000)
+  -t THRESHOLD, --threshold THRESHOLD
+                        threshold for convergence (default: 1e-40)
+  -v, --verbose
+
+

jrun

+
usage: bussilab jrun [-h] [-d] [--lab] [--port PORT] [--screen-cmd SCREEN_CMD]
+                     [--screen-log SCREEN_LOG] [--python-exec PYTHON_EXEC]
+                     [-S SOCKNAME] [--no-screen] [--keep-ld-library-path]
+                     [--detach]
+
+Run jupyter server
+
+options:
+  -h, --help            show this help message and exit
+  -d, --dry-run         show command instead of executing it (default: False)
+  --lab                 use jupyterlab (default: False)
+  --port PORT           set port (default: 0)
+  --screen-cmd SCREEN_CMD
+                        screen command (default: screen)
+  --screen-log SCREEN_LOG
+                        screen logfile (no logfile by default) (default: )
+  --python-exec PYTHON_EXEC
+                        python executable (default: )
+  -S SOCKNAME, --sockname SOCKNAME
+                        screen sockname (default: (path):(port):jupyter)
+  --no-screen           do not run screen (default: False)
+  --keep-ld-library-path
+                        (ignored, this is the default now) (default: False)
+  --detach              detach screen (default: False)
+
+

This is a tool to run a jupyter server within a screen command. +The typical usage would be

+
cd /path/to/your/notebook/dir
+bussilab jrun
+
+

A free port is identified first (can be overridden with the --port +option) and a jupyter server is then run +inside a screen instance. +You will thus have to type CTRL+aCTRL+d in order to detach the screen +letting it run in the background.

+

Alternatively, you can immediately detach the screen with

+
cd /path/to/your/notebook/dir
+bussilab jrun --detach
+
+

Notice that, since the server is run inside a screen instance, in order +to visualize python outputs that has been sent directly to the terminal you +should connect to the screen instance later. By default, a socket name +containing the path where the server is running is used, with / replaced +by :. It should thus be easy to use screen -ls to find the proper screen +instance.

+

jremote

+
usage: bussilab jremote [-h] [-d] [-l] [--port PORT] [-i INDEX]
+                        [--python-exec PYTHON_EXEC] [--server-url SERVER_URL]
+                        [--open-cmd OPEN_CMD]
+                        server
+
+Run jupyter client
+
+positional arguments:
+  server                server URL (e.g. giorgione.phys.sissa.it)
+
+options:
+  -h, --help            show this help message and exit
+  -d, --dry-run         show command instead of executing it (default: False)
+  -l, --list-only       only report a list or servers (default: False)
+  --port PORT           set port (default: 0)
+  -i INDEX, --index INDEX
+                        choose server, by default interactive choice (default:
+                        0)
+  --python-exec PYTHON_EXEC
+                        remote python executable (e.g. module load python3
+                        python-home; python) (default: python)
+  --server-url SERVER_URL
+                        URL on server (default: choose interactively)
+                        (default: )
+  --open-cmd OPEN_CMD   open command (detected automatically by default)
+                        (default: )
+
+

This is a tool to connect to a remote running jupyter server. +The typical usage would be

+
bussilab jremote server.url
+
+

A list of jupyter servers running on the selected machines will be +shown, and one of them can be picked typing its progressive number. +In case there is a single server running, it will be opened by default.

+

Notice that if the name of the python executable on the server is +different from plain python you can override it with +--python-exec. You can also run other scripts before, for instance +loading relevant modules:

+
bussilab jremote giorgione.phys.sissa.it --python-exec            --python-exec "module load python3 python-home; python3"
+
+

If you recurrently connect to the same workstation, it is convenient +to write a small script like this one, call it jremote and put it in +your path:

+
export PYTHONPATH=/path/to/bussilab/source
+python -m bussilab jremote giorgione.phys.sissa.it --python-exec "module load python3 python-home ; python3"
+
+

Here replace python with the name of your python interpreter (might be +python3.7).

+

pip_upgrade_all

+
usage: bussilab pip_upgrade_all [-h] [--user]
+
+Upgrade all packages with pip
+
+options:
+  -h, --help  show this help message and exit
+  --user      install/upgrade in user location (default: False)
+
+

This is a tool to upgrade all your packages with pip. +It is a convenient way to upgrade all the packages without +the need to list them explicitly.

+

Warning: this uses pip, so it might not work as expected +if you are working in conda.

+

The typical usage would be

+
bussilab pip_upgrade_all
+
+

If you installed packages in your home you should use

+
bussilab pip_upgrade_all --user
+
+

notify

+
usage: bussilab notify [-h] [-m MESSAGE]
+                       [-c CHANNEL | -u UPDATE | -d DELETE | -r REPLY | -R REPLY_BROADCAST | -X REACT]
+                       [-f FILE] [-t TITLE] [--no-footer]
+                       [--screenlog SCREENLOG]
+                       [--screenlog-maxlines SCREENLOG_MAXLINES] [--type TYPE]
+                       [--token TOKEN] [-q]
+
+Send a notification to Slack
+
+options:
+  -h, --help            show this help message and exit
+  -m MESSAGE, --message MESSAGE
+                        message (default: None)
+  -c CHANNEL, --channel CHANNEL
+                        channel (check ~/.bussilabrc by default) (default:
+                        None)
+  -u UPDATE, --update UPDATE
+                        url of the message to be updated (default: None)
+  -d DELETE, --delete DELETE
+                        url of the message to be deleted (default: None)
+  -r REPLY, --reply REPLY
+                        url of the message to be replied (default: None)
+  -R REPLY_BROADCAST, --reply-broadcast REPLY_BROADCAST
+                        url of the message to be broadcast-replied (default:
+                        None)
+  -X REACT, --react REACT
+                        react to a message (default: None)
+  -f FILE, --file FILE  path to a file to be uploaded (incompatible with -u
+                        and -d) (default: None)
+  -t TITLE, --title TITLE
+                        title of the message (default: None)
+  --no-footer           ignore footer (default: False)
+  --screenlog SCREENLOG
+                        screenlog file (default: None)
+  --screenlog-maxlines SCREENLOG_MAXLINES
+                        maximum number of lines in screenlog (0 means all)
+                        (default: 0)
+  --type TYPE           'plain_text' or 'mrkdwn' (default: mrkdwn)
+  --token TOKEN         token (check ~/.bussilabrc by default (default: None)
+  -q, --quiet           quiet (do not write output) (default: False)
+
+

This is a tool to send a notification to Slack. +See the documentation of bussilab.notify.

+

cron

+
usage: bussilab cron [-h] [--quick-start]
+                     [--quick-start-skip-steps QUICK_START_SKIP_STEPS]
+                     [--quick-start-event QUICK_START_EVENT]
+                     [--cron-file CRON_FILE] [--screen-cmd SCREEN_CMD]
+                     [--screen-log SCREEN_LOG] [--no-screen]
+                     [--keep-ld-library-path] [-S SOCKNAME]
+                     [--python-exec PYTHON_EXEC] [--detach] [--unique]
+                     [--window] [--period PERIOD] [--max-times MAX_TIMES]
+
+Run cron
+
+options:
+  -h, --help            show this help message and exit
+  --quick-start         run immediately (default: False)
+  --quick-start-skip-steps QUICK_START_SKIP_STEPS
+                        skip steps on quick start (default: None)
+  --quick-start-event QUICK_START_EVENT
+                        event number for quick start (default: None)
+  --cron-file CRON_FILE
+                        path to cron file (default: None)
+  --screen-cmd SCREEN_CMD
+                        screen command (default: screen)
+  --screen-log SCREEN_LOG
+                        screen logfile (no logfile by default) (default: )
+  --no-screen           do not run screen (default: False)
+  --keep-ld-library-path
+                        (ignored, this is the default now) (default: False)
+  -S SOCKNAME, --sockname SOCKNAME
+                        screen sockname (default: (path):cron)
+  --python-exec PYTHON_EXEC
+                        python executable (default: )
+  --detach              detach screen (default: False)
+  --unique              allow only one screen with this socket (default:
+                        False)
+  --window              run a new window within the same screen (default:
+                        False)
+  --period PERIOD       period (seconds) default read from cron file or set to
+                        3600 (default: None)
+  --max-times MAX_TIMES
+                        maximum number of calls (default: None)
+
+

required

+
usage: bussilab required [-h] [--macports | --conda] [--pyver PYVER]
+
+print requirements
+
+options:
+  -h, --help     show this help message and exit
+  --macports     conda syntax (default: False)
+  --conda        macports syntax (default: False)
+  --pyver PYVER  pyversion (e.g. 38), for macports only (default: )
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/clustering.html b/bussilab/clustering.html new file mode 100644 index 0000000..dce562a --- /dev/null +++ b/bussilab/clustering.html @@ -0,0 +1,227 @@ + + + + + + +bussilab.clustering API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.clustering

+
+
+

Module with some clustering tools

+
+
+
+
+
+
+

Functions

+
+
+def daura(adj, weights=None, *, min_size=0, max_clusters=None) +
+
+

Clustering algorithm introduced in Daura et al, Angew. Chemie (1999).

+

WARNING: important fix in v0.0.39 for version with weights

+

Parameters

+
+
adj : array_like, square matrix
+
adj[i,j] contains 1 (or True) if frames i and j are adjacent, 0 (or False) otherwise.
+
weights : array_like, optional
+
weights[i] contains the weight of the i-th frame.
+
min_size : number
+
Minimum cluster size. Clusters smaller than this size are not reported. +When using weights, the cluster size is defined as the sum of the weights of +the members of the cluster.
+
max_clusters : int
+
Maximum number of clusters.
+
+

Example

+
import scipy.spatial.distance as distance
+dist=distance.squareform(distance.pdist(trajectory))
+clustering.daura(dist<0.7)
+
+
+
+def max_clique(adj, weights=None, *, min_size=0, max_clusters=None, use_networkit=False) +
+
+

Clustering algorithm used in Reisser et al, NAR (2020).

+

Parameters

+
+
adj : array_like, square matrix
+
adj[i,j] contains 1 (or True) if frames i and j are adjacent, 0 (or False) otherwise.
+
weights : array_like, optional
+
weights[i] contains the weight of the i-th frame.
+
min_size : number
+
Minimum cluster size. Clusters smaller than this size are not reported. +When using weights, the cluster size is defined as the sum of the weights of +the members of the cluster.
+
max_clusters : int
+
Maximum number of clusters.
+
use_networkit : bool, optional
+
if True, use a networkit implementation that seems to be faster. +It requires python package networkit to be installed in advance!
+
+

Example

+
import scipy.spatial.distance as distance
+dist=distance.squareform(distance.pdist(trajectory))
+clustering.max_clique(dist<0.7)
+
+
+
+def qt(distances, cutoff, weights=None, *, min_size=0, max_clusters=None) +
+
+

Quality threshold clustering.

+

The method is explained in the original paper. +The implementation has been adapted from this one, +which is also released under a GPL licence. +Thus, if you use this algorithm please cite this article, +which also discusses the important differences between this algorithm and the Daura et al algorithm +in the context of analysing molecular dynamics simulations. +Additionally, mention which exact version of the bussilab package you used.

+

The implementation included here, at variance with the original one, allows passing weights +and can be used with arbitrary metrics. In addition, it also reports clusters of size 1 +(unless one passes max_clusters>1). The code is optimized when compared with the original one, +and speed can be further increased by passing np.array(distances,dtype='float32') to distances.

+

WARNING: important fix in v0.0.39 for version with weights

+

As of version v0.0.40, clusters with the same number of members are prioritized based on their +diameter (smaller diameter gets the priority). This is expected to make non-weighted calculations +more reproducible, but might change some results when compared with previous versions. +In addition, when growing a single candidate cluster, it two points are at the same +distance from the growing cluster the one with higher weight is chosen. With these +priorities, any choice where either (a) weights are float or (b) distances are float +should lead to deterministing clustering irrespective of roundoff errors, assuming +floats are never identical.

+

Parameters

+
+
distances : array_like, square matrix
+
distances[i,j] contains the distance between i and j frame.
+
cutoff : number
+
maximum distance for two frames to be included in the same cluster
+
weights : array_like, optional
+
weights[i] contains the weight of the i-th frame.
+
min_size : number
+
Minimum cluster size. Clusters smaller than this size are not reported. +When using weights, the cluster size is defined as the sum of the weights of +the members of the cluster.
+
max_clusters : int
+
Maximum number of clusters.
+
+

Example

+
import scipy.spatial.distance as distance
+dist=distance.squareform(distance.pdist(trajectory))
+clustering.qt(dist,0.7)
+
+clustering.qt(np.array(dist,dtype='float32')) # should be slightly faster
+
+
+
+
+
+

Classes

+
+
+class ClusteringResult +(*, method: str, clusters: list, weights: Optional[list]) +
+
+

Result of a bussilab.clustering calculation.

+
+ +Expand source code + +
class ClusteringResult(Result):
+    """Result of a `bussilab.clustering` calculation."""
+    def __init__(self,
+                *,
+                method: str,
+                clusters: list,
+                weights: Optional[list]
+                ):
+        self.method = method
+        """`str` containing the name of the method used."""
+        self.clusters = clusters
+        """`list of lists` containing the members of each cluster."""
+        self.weights = weights
+        """`list` containing the weights of the clusters."""
+
+

Ancestors

+ +

Instance variables

+
+
var clusters
+
+

list of lists containing the members of each cluster.

+
+
var method
+
+

str containing the name of the method used.

+
+
var weights
+
+

list containing the weights of the clusters.

+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/coretools.html b/bussilab/coretools.html new file mode 100644 index 0000000..a4f6e33 --- /dev/null +++ b/bussilab/coretools.html @@ -0,0 +1,358 @@ + + + + + + +bussilab.coretools API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.coretools

+
+
+

General purpose tools.

+
+
+
+
+
+
+

Functions

+
+
+def cd(newdir: os.PathLike, *, create: bool = False) +
+
+

Context manager to temporarily change working directory.

+

Can be used to change working directory temporarily making sure that at the +end of the context the working directory is restored. Notably, +it also works if an exception is raised within the context.

+

Parameters

+
+
newdir : path
+
Path to the desired directory.
+
create : bool (default False)
+
Create directory first. +If the directory exists already, no error is reported
+
+

Examples

+
from bussilab.coretools import cd
+with cd("/path/to/dir"):
+    do_something() # this is executed in the /path/to/dir directory
+do_something_else() # this is executed in the original directory
+
+
+
+def config(path: Optional[os.PathLike] = None) +
+
+
+
+
+def config_path(path: Optional[os.PathLike] = None) +
+
+
+
+
+def ensure_np_array(arg) ‑> Optional[numpy.ndarray] +
+
+

Convert arg to np.array if necessary.

+
+
+def file_or_path(arg, mode: str) +
+
+

Convert a path to an open file object if necessary.

+
+
+def import_numba_jit() +
+
+

Return a numba.njit object. If import fails, return a fake jit object and emits a warning.

+

Currently, the returned object can only be used as @njit (no option). It might be extended +to allow more jit options.

+
+
+
+
+

Classes

+
+
+class Result +(*args, **kwargs) +
+
+

Base class for objects returning results.

+

It allows one to create a return type that is similar to those +created by scipy.optimize.minimize. +The string representation of such an object contains a list +of attributes and values and is easy to visualize on notebooks.

+

Examples

+

The simplest usage is this one:

+
from bussilab import coretools
+
+class MytoolResult(coretools.Result):
+    """Result of a mytool calculation."""
+    pass
+
+def mytool():
+    a = 3
+    b = "ciao"
+    return MytoolResult(a=a, b=b)
+
+m=mytool()
+print(m)
+
+

Notice that the class variables are dynamic: any keyword argument +provided in the class constructor will be processed. +If you want to enforce the class attributes you should add an explicit +constructor. This will also allow you to add pdoc docstrings. +The recommended usage is thus:

+
from bussilab import coretools
+
+class MytoolResult(coretools.Result):
+    """Result of a mytool calculation."""
+    def __init__(a, b):
+        super().__init__()
+        self.a = a
+        """Documentation for attribute a."""
+        self.b = b
+        """Documentation for attribute b."""
+
+def mytool():
+    a = 3
+    b = "ciao"
+    return MytoolResult(a=a, b=b)
+
+m = mytool()
+print(m)
+
+
+ +Expand source code + +
class Result(dict):
+    # triple ' instead of triple " to allow using docstrings in the example
+    '''Base class for objects returning results.
+
+       It allows one to create a return type that is similar to those
+       created by `scipy.optimize.minimize`.
+       The string representation of such an object contains a list
+       of attributes and values and is easy to visualize on notebooks.
+
+       Examples
+       --------
+
+       The simplest usage is this one:
+
+       ```python
+       from bussilab import coretools
+
+       class MytoolResult(coretools.Result):
+           """Result of a mytool calculation."""
+           pass
+
+       def mytool():
+           a = 3
+           b = "ciao"
+           return MytoolResult(a=a, b=b)
+
+       m=mytool()
+       print(m)
+       ```
+
+       Notice that the class variables are dynamic: any keyword argument
+       provided in the class constructor will be processed.
+       If you want to enforce the class attributes you should add an explicit
+       constructor. This will also allow you to add pdoc docstrings.
+       The recommended usage is thus:
+
+       ````
+       from bussilab import coretools
+
+       class MytoolResult(coretools.Result):
+           """Result of a mytool calculation."""
+           def __init__(a, b):
+               super().__init__()
+               self.a = a
+               """Documentation for attribute a."""
+               self.b = b
+               """Documentation for attribute b."""
+
+       def mytool():
+           a = 3
+           b = "ciao"
+           return MytoolResult(a=a, b=b)
+
+       m = mytool()
+       print(m)
+       ````
+
+    '''
+
+    def __getattr__(self, name: str):
+        try:
+            return self[name]
+        except KeyError:
+            raise AttributeError(name)
+
+    def __setattr__(self, item: str, value):
+        self[item] = value
+
+    def __delattr__(self, item: str):
+        del self[item]
+
+    def __repr__(self) -> str:
+        if self.keys():
+            m = max(map(len, list(self.keys()))) + 1
+# when used recursively, the inner repr is properly indented:
+            return '\n'.join([k.rjust(m) + ': ' + re.sub("\n", "\n"+" "*(m+2), repr(v))
+                              for k, v in sorted(self.items())])
+        return self.__class__.__name__ + "()"
+
+    def __dir__(self) -> List[str]:
+        return list(sorted(self.keys()))
+
+

Ancestors

+
    +
  • builtins.dict
  • +
+

Subclasses

+ +
+
+class TestCase +(methodName='runTest') +
+
+

Improved base class for test cases.

+

Extends the unittest.TestCase class with some additional assertion.

+

Create an instance of the class that will use the named test +method when executed. Raises a ValueError if the instance does +not have a method with the specified name.

+
+ +Expand source code + +
class TestCase(unittest.TestCase):
+    """Improved base class for test cases.
+
+       Extends the `unittest.TestCase` class with some additional assertion.
+
+    """
+    def assertEqualFile(self, file1: os.PathLike, file2: Optional[os.PathLike] = None):
+        """Check if two files are equal.
+
+           Parameters
+           ----------
+
+           file1: path
+               Path to the first file
+
+           file2: path, optional
+               Path to the second file. If not provided, defaults to `file1+".ref"`.
+        """
+        if file2 is None:
+            file2 = pathlib.PurePath(str(file1)+".ref")
+
+        try:
+            f1=open(file1, "r")
+        except FileNotFoundError:
+            self.fail("file " +str(file1) + " was not found")
+
+        try:
+            f2=open(file2, "r")
+        except FileNotFoundError:
+            self.fail("file " +str(file2) + " was not found")
+
+        with f1:
+            with f2:
+                self.assertEqual(f1.read(), f2.read())
+
+

Ancestors

+
    +
  • unittest.case.TestCase
  • +
+

Methods

+
+
+def assertEqualFile(self, file1: os.PathLike, file2: Optional[os.PathLike] = None) +
+
+

Check if two files are equal.

+

Parameters

+
+
file1 : path
+
Path to the first file
+
file2 : path, optional
+
Path to the second file. If not provided, defaults to file1+".ref".
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/cron.html b/bussilab/cron.html new file mode 100644 index 0000000..1cdb510 --- /dev/null +++ b/bussilab/cron.html @@ -0,0 +1,69 @@ + + + + + + +bussilab.cron API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.cron

+
+
+
+
+
+
+
+
+

Functions

+
+
+def cron(*, quick_start: bool = False, quick_start_skip_steps: int = 0, quick_start_event: int = 0, cron_file: str = '', screen_cmd: str = 'screen', screen_log: str = '', no_screen: bool = True, keep_ld_library_path: bool = True, sockname: str = '(path):cron', python_exec: str = '', detach: bool = False, period: Optional[int] = None, max_times: Optional[int] = None, unique: bool = False, window: bool = False) +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/index.html b/bussilab/index.html new file mode 100644 index 0000000..4580802 --- /dev/null +++ b/bussilab/index.html @@ -0,0 +1,440 @@ + + + + + + +bussilab API documentation + + + + + + + + + + + +
+
+
+

Package bussilab

+
+
+

A package collecting a heterogeneous set of tools.

+

This package collects a number of tools that are useful enough +to be distributed but too small to deserve being published as +separate packages. +Source code is on GitHub. +Submodules are listed at the end of the current page. +Command-line tools are described at this page. +A test pdf manual is available here. +This is the documentation for version 0.0.45.

+

Install

+

This package is only compatible with Python >=3.6 (no compatibility with Python 2!). +The recommended way to install this package depends on how you prefer to manage your +python dependencies.

+

pip. +If you manage your dependencies with pip and install packages in your home, use:

+
pip install --user bussilab
+# make sure the user installed packages can be imported, or add this to your python path
+export PYTHONPATH="$(python -c 'import site; print(site.USER_SITE)'):$PYTHONPATH"
+# make sure the bussilab script is your execution the path, or add this to your shell path
+export PATH="$(python -c 'import site; print(site.USER_BASE + "/bin")'):$PATH"
+
+

Required packages will be downloaded and installed automatically in your home.

+

pip + venv. +If you manage your dependencies with pip and work in a virtual +environment, use:

+
pip install bussilab
+
+

Required packages will be downloaded and installed automatically in the virtual +environment.

+

conda. +If you manage your dependencies with conda, use:

+
conda install -c conda-forge -c bussilab py-bussilab
+
+

Required packages will be downloaded and installed automatically in the active +conda environment.

+

macports. +If you manage your dependencies with macports you might prefer to install required packages +first. Since the list of requirements might change, it is recommended to use +the bussilab package itself to obtain the list of requirements. +You can do it as follows: +1

+
# install pip and setuptools first
+sudo port install py39-pip py39-setuptools
+# install a bare version of the package, without dependencies
+pip-3.9 install --user --no-deps bussilab
+# make sure the user installed packages can be imported, or add this to your python path
+export PYTHONPATH="$(python3.9 -c 'import site; print(site.USER_SITE)'):$PYTHONPATH"
+# make sure the bussilab script is your execution the path, or add this to your shell path
+export PATH="$(python3.9 -c 'import site; print(site.USER_BASE + "/bin")'):$PATH"
+# install the dependencies
+sudo port install $(bussilab required --macports --pyver 39)
+
+

Notice that the list of required packages might change. It is +thus recommended to run the commands above every time you update the bussilab +package.

+

Checking the installation

+

Once the package is installed you should be able to import the module from the python interpreter:2

+
import bussilab
+# this command can be used to check if all dependencies are in place:
+bussilab.import_submodules()
+
+

You should also have access to an executable script that can be used from the command line:3

+
bussilab -h
+# this command can be used to check if all dependencies are in place:
+bussilab check --import
+
+

Setting autocompletion

+

In order to benefit from autocompletion for the executable script you should +install the argcomplete package +(with pip, conda, or macports) +and add the following command to your .bashrc file:4

+
eval "$(register-python-argcomplete bussilab)"
+
+

Getting started

+

Python

+

The bussilab module itself only contains some basic infrastructure. +Most of the features are implemented in the submodules listed at the end of +this page. +Submodules should be explicitly imported using, e.g.:

+
from bussilab import wham
+
+

Check their documentation to see how to use them.

+

If you are using Python >=3.7, you can directly use the submodules +without importing them explicitly, e.g.:

+
import bussilab as bl
+bl.wham.wham()
+
+

Examples

+

In the examples directory you can find a number of notebooks +that can be used as a source of inspiration.

+

Command line

+

In addition, the bussilab script allows to access some functionality +directly from the command line, without entering python. +For instance, you can execute the wham subcommand typing

+
bussilab wham
+
+

Check their documentation in the cli_documentation submodule.

+

Advanced stuff

+

Notice that instructions below assume you are using pip. +If you use conda or macports you might have to adjust the commands.

+

Install with no dependencies

+

You might want to ignore dependencies completely:

+
pip install --no-deps bussilab
+
+

If you proceed this way, you will still be able to import bussilab module and +to execute the bussilab script, but some of the submodules might not be importable. +The following command will report which submodules can be used then:

+
bussilab check --import
+
+

The result will depend on which of the required packages are already installed on +your system.

+

Building documentation

+

You can build the documentation using pdoc3:

+
pip install pdoc3
+pdoc3 -f --html -o doc/ bussilab
+
+

Documentation will be visible at doc/bussilab/index.html. +This is normally not necessary, since +the pre-built documentation of the latest version can be found at this link, +but can be useful to test changes to the documentation before pushing them to GitHub.

+

Implementing your modifications

+

If you want to modify the Python source code you should download it from GitHub:

+
git clone https://github.com/bussilab/py-bussilab.git
+cd py-bussilab
+
+

Since the module is +written in pure python,5 it can be used by just adding its path to PYTHONPATH +and the bin directory to PATH:

+
export PATH="/path/to/py-bussilab/bin:$PATH"
+export PYTHONPATH="/path/to/py-bussilab:$PYTHONPATH"
+
+

Testing the code

+

If you modified the code, it is recommended to test that your changes did not break +existing features.

+

You can run the tests using pytest:

+
pip install pytest
+pytest
+
+

All tests should succeed. Notice that the tests will import the bussilab module. +Thus, if you want the version modified by you to be tested (and not another version +that you might have installed with pip already) you should properly set +the PYTHONPATH variable as explained above.

+

Static types can be checked using mypy:

+
pip install mypy
+mypy bussilab
+
+

This check should succeed.

+

Other static checks can be done with pyflakes:

+
pip install pyflakes
+pyflakes bussilab
+
+

This check should succeed.

+

Correct code formatting can be checked using pylint:

+
pip install pylint
+pylint -E bussilab
+
+

This check should succeed.

+

Running and rendering jupyter examples from the command line

+

The GitHub repository also contains jupyter examples. +You can rerun all the jupyter examples from the command line:

+
cd examples
+pip install jupyter jupyter_contrib_nbextensions matplotlib
+./rerun.sh
+
+

You can render all the jupyter examples as html from the command line:

+
cd examples
+pip install jupyter nbconvert
+./render.sh
+
+
+
+
    +
  1. +

    Notice that on macports the name of the python executable is python3.9 +and the name of the pip installer is pip-3.9. +A different python version should work as well. 

    +
  2. +
  3. +

    If you installed the package using the --user option, in order to be able to import +the package you will have to make sure that the directory returned by the command +python -c 'import site; print(site.USER_SITE)' is included in your python search path. +If not, you can add it to the environment variable PYTHONPATH

    +
  4. +
  5. +

    If you installed the package using the --user option, in order to be able to execute +the script you will have to make sure that the directory returned by the command +python -c 'import site; print(site.USER_BASE + "/bin")' is included in your PATH +environment variable. Alternatively, if the bussilab script is not in your +PATH you can run it as python -m bussilab -h

    +
  6. +
  7. +

    If you are using macports, the command would be +eval "$(register-python-argcomplete-3.9 bussilab)"

    +
  8. +
  9. +

    This might change in the future. 

    +
  10. +
+
+
+
+

Sub-modules

+
+
bussilab.ann
+
+

Module with artificial neural networks …

+
+
bussilab.cli
+
+

Tools to implement the command line interface +…

+
+
bussilab.cli_documentation
+
+

Documentation for command line tools +…

+
+
bussilab.clustering
+
+

Module with some clustering tools

+
+
bussilab.coretools
+
+

General purpose tools.

+
+
bussilab.cron
+
+
+
+
bussilab.jremote
+
+

Module implementing tools for remote jupyter connections …

+
+
bussilab.lohman
+
+

Module implementing Lohman model for helicases.

+
+
bussilab.maxent
+
+

Tools to perform reweighting using MaxEnt.

+
+
bussilab.notify
+
+

Module implementing Slack notifications …

+
+
bussilab.pip
+
+

Module implementing a small tool for installing and updating packages with pip.

+
+
bussilab.potts
+
+

Module containing a tool to solve Potts models by enumeration …

+
+
bussilab.reports
+
+
+
+
bussilab.wham
+
+

Module containing a WHAM implementation …

+
+
+
+
+
+
+

Functions

+
+
+def describe_submodule(module: str) ‑> str +
+
+

Return a short description of a submodule without importing it.

+

Parameters

+
+
module : str
+
Name of the module.
+
+

Returns

+
+
str
+
The docstring of the module. If the docstring is not present, +returns an empty string. If an empy string is passed as module, +the docstring of the main package is returned.
+
+

Raises

+
+
ModuleNotFoundError
+
If the module does not exist.
+
+

Examples

+
from bussilab import describe_submodule
+print(describe_submodule("lohman"))
+
+
+
+def import_submodules() ‑> None +
+
+

Import all the available submodules.

+

The main bussilab module does not explicitly import +the available submodules so as not to slow down the behavior +of the command line interface and to allow importing individual modules +even if not all the dependencies of the other modules are installed. +Use this function to import all the submodules (might take a few seconds).

+

Mostly for testing that the packages required by the available +submodules are installed, but it can also be used +to preload all the submodules (and required packages) making them load faster later.

+

Raises

+

If one or more submodules cannot be imported it will raise an Exception.

+
+
+def list_submodules() ‑> List[str] +
+
+

Return a list of all the available submodules.

+

It can be used to quickly show which submodules are available for importing.

+

Returns

+
+
list
+
A list of names of available submodules.
+
+

Examples

+

Print the available submodules and a short description for each of them.

+
from bussilab import list_submodules, describe_submodule
+for m in list_submodules():
+    print(m, describe_submodule(m))
+
+
+
+def required_conda() ‑> str +
+
+
+
+
+def required_macports(pyver='') ‑> str +
+
+
+
+
+def required_pip() ‑> str +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/jremote.html b/bussilab/jremote.html new file mode 100644 index 0000000..cc0445e --- /dev/null +++ b/bussilab/jremote.html @@ -0,0 +1,91 @@ + + + + + + +bussilab.jremote API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.jremote

+
+
+

Module implementing tools for remote jupyter connections.

+

This module contains some utilities that are mostly designed +to be used as command line tools. The interface of the functions defined in +this module is subject to changes. One should instead use the subcommands +jrun and jremote in the cli_documentation +submodule.

+
+
+
+
+
+
+

Functions

+
+
+def find_free_port() +
+
+

Returns the number of a free port.

+
+
+def remote(server: str, python_exec: str = 'python', dry_run: bool = False, list_only: bool = False, server_url: str = '', port: int = 0, index: int = 0, open_cmd: str = '') +
+
+
+
+
+def run_server(dry_run: bool = False, port: int = 0, screen_cmd: str = 'screen', screen_log: str = '', no_screen: bool = False, keep_ld_library_path: bool = True, python_exec: str = '', sockname: str = '(path):(port):jupyter', lab: bool = False, detach: bool = False) +
+
+

Runs a jupyter server inside a screen command.

+

This function is only designed to be used as a command line +tool.

+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/lohman.html b/bussilab/lohman.html new file mode 100644 index 0000000..43e1cb8 --- /dev/null +++ b/bussilab/lohman.html @@ -0,0 +1,94 @@ + + + + + + +bussilab.lohman API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.lohman

+
+
+

Module implementing Lohman model for helicases.

+
+
+
+
+
+
+

Functions

+
+
+def lohman(t, ku: float, kd: float, n: int = 1, boundaries: Tuple[float, float] = (0.0, 1.0)) ‑> Union[float, numpy.ndarray] +
+
+

Lohman model for helicases.

+

Compute the fraction of unwound helices as a function of time. +See Lucius et al, Biophys J 2003.

+

Parameters

+
+
t : float or sequence or np.ndarray
+
Time. If a sequence or np.ndarray is provided, the function is computed +for all values and an array is returned.
+
ku : float
+
Unwinding rate.
+
kd : float
+
Dissociation rate.
+
n : int, optional
+
Step size
+
boundaries : tuple with 2 elements
+
Result is mapped to this range.
+
+

Returns

+
+
float or np.ndarray
+
The fraction of unfolded helices at a given time t. If an array is provided for t, +an array is returned containing the fractions at all the times. +If boundaries is provided, the fraction is linearly mapped into the +boundaries[0], boundaries[1] range.
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/maxent.html b/bussilab/maxent.html new file mode 100644 index 0000000..83aa27a --- /dev/null +++ b/bussilab/maxent.html @@ -0,0 +1,236 @@ + + + + + + +bussilab.maxent API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.maxent

+
+
+

Tools to perform reweighting using MaxEnt.

+
+
+
+
+
+
+

Functions

+
+
+def maxent(traj, reference, *, logW=None, maxiter: int = 1000, verbose: bool = False, lambdas=None, l2=None, l1=None, method: str = 'L-BFGS-B', regularization: Optional[Callable] = None, tol: Optional[float] = None, options=None, cuda=False) +
+
+

Tool that computes new weights to enforce reference values.

+

This tools process a an array containing the observables computed along a trajectory and +returns new weights that satisfy the maximum entropy principle and so that weighted averages +agree with reference values.

+

Parameters

+
+
traj : array_like
+
A 2D array (lists or tuples are internally converted to numpy arrays). +traj[i,j] is j-th observable computed in the i-th frame. +If traj is a CUDAMatrix object, then cudamat is used irrespectively of the +bool parameter cuda.
+
reference : array_like
+
A 1D array (lists or tuples are internally converted to numpy arrays) +containing the reference values to be enforced. If the i-th element is a tuple +or an array with 2 elements, they are interpreted as boundaries. For instance, +reference=[1.0,(2.0,3.0)] will make sure the first observable has value 1 and +the second observable is within the range (2,3). Boundaries equal to +np.inf +or -np.inf can be used to imply no boundary. Notice that boundaries in the +form (A,B) where both A and B are finite are implemented by adding fictitious +variables in a way that is transparent to the user. +Boundaries in the form +(A,B) where one of A or B is finite and the other is infinite are implemented +as boundaries on lambdas. +Boundaries in the form (A,A) are interpreted as +constraints.
+
logW : array_like
+
A 1D array (lists or tuples are internally converted to numpy arrays) +containing the logarithm of the a priori weight of the provided frames.
+
lamdbas : array_like
+
A 1D array with initial values of lambda. A good guess will minimize faster. A +typical case would be recycling the lambdas obtained with slighlty different +regularization parameters.
+
l2 : None, float, or array_like
+
Prefactor for L2 regularization. If None, no regularization is applied. If +float, the same factor is used on all the lambdas. +If it is an array, it +should have length equal to len(reference).
+
l1 : None, float, or array_like
+
Prefactor for L1 regularization. If None, no regularization is applied. If +float, the same factor is used on all the lambdas. +If it is an array, it +should have length equal to len(reference).
+
regularization : callable or None
+
A function that takes as argument the current lambdas and return an tuple +containing the regularization function and its derivatives. For instance, +passing a function defined as +def reg(x): return (0.0001*0.5*np.sum(x**2),0.0001*x) +is equivalent to passing l2=0.0001.
+
verbose : bool
+
If True, progress informations are written on stdout.
+
method : str
+
Minimization method. See documentation of scipy.optimize.minimize.
+
maxiter : int
+
Maximum number of iterations
+
tol : float or None
+
Tolerance for minimization. See documentation of scipy.optimize.minimize.
+
options : dict
+
Arbitrary options passed to scipy.optimize.minimize.
+
cuda : bool or None (default False)
+
Use cuda. If None, chosen based on the availability of the cudamat library.
+
+

Notes On Using Cuda

+

Note that for normal datasets the cost of transfering the traj object to +the GPU dominates. It it however possible to transfer the traj object first to the GPU +with cu_traj=cm.CUDAMatrix(traj) and then reuse it for multiple calls +(e.g. for a hyper parameter scan).

+
+
+
+
+

Classes

+
+
+class MaxentResult +(*, logW_ME: numpy.ndarray, lambdas: numpy.ndarray, averages: numpy.ndarray, gamma: float, success: bool, message: str, nfev: int, nit: int) +
+
+

Result of a maxent() calculation.

+
+ +Expand source code + +
class MaxentResult(coretools.Result):
+    """Result of a `bussilab.maxent.maxent` calculation."""
+    def __init__(self,
+                 *,
+                 logW_ME: np.ndarray,
+                 lambdas: np.ndarray,
+                 averages: np.ndarray,
+                 gamma: float,
+                 success: bool,
+                 message: str,
+                 nfev: int,
+                 nit: int):
+        super().__init__()
+        self.logW_ME = logW_ME
+        """`np.ndarray` with `traj.shape[0]` elements, logarithms of the optimized weights."""
+        self.lambdas = lambdas
+        """`np.ndarray` with `len(reference)` elements, optimized Lagrangian multipliers."""
+        self.averages = averages
+        """`np.ndarray` with `len(reference)` elements, resulting averages."""
+        self.gamma = gamma
+        """`float` containing the resulting likelihood Gamma."""
+        self.success = success
+        """`bool` reporting the success of the minimizer."""
+        self.message = message
+        """`str` reporting the possible reason of failuer of the minimizer."""
+        self.nfev = nfev
+        """`int` reporting the number of function evaluations."""
+        self.nit = nit
+        """`int` reporting the number of iterations in the minimization procedure."""
+
+

Ancestors

+ +

Instance variables

+
+
var averages
+
+

np.ndarray with len(reference) elements, resulting averages.

+
+
var gamma
+
+

float containing the resulting likelihood Gamma.

+
+
var lambdas
+
+

np.ndarray with len(reference) elements, optimized Lagrangian multipliers.

+
+
var logW_ME
+
+

np.ndarray with traj.shape[0] elements, logarithms of the optimized weights.

+
+
var message
+
+

str reporting the possible reason of failuer of the minimizer.

+
+
var nfev
+
+

int reporting the number of function evaluations.

+
+
var nit
+
+

int reporting the number of iterations in the minimization procedure.

+
+
var success
+
+

bool reporting the success of the minimizer.

+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/notify.html b/bussilab/notify.html new file mode 100644 index 0000000..fdc5927 --- /dev/null +++ b/bussilab/notify.html @@ -0,0 +1,180 @@ + + + + + + +bussilab.notify API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.notify

+
+
+

Module implementing Slack notifications.

+

This module sends notification through an App installed in the Slack workspace. +Some settings are needed first for authentication. It is recommended to add a +file named .bussilabrc to your home directory with the following content:

+
notify:
+  token: xoxb-00000
+  channel: U00000
+
+

The token here should be provided by the administrator of your workspace. +The channel should be the Slack ID associated to your user. It can be found +looking in your Slack profile. With these settings, the tool will send +notifications to you by default.

+

Notifications can then be sent using either the command line:

+
bussilab notify --message "text here"
+
+

or from python:

+
from bussilab.notify import notify
+notify("text here")
+
+

Notice that the message is optional. Even with an empty message, the footer +will allow you to reconstruct from which machine and directory the message was +sent from. This might be sufficient for your goal.

+

You can also indicate a specific channel for the notification using the +channel option:

+
bussilab notify --message "text here" --channel "project-myproject"
+
+

or from python:

+
from bussilab.notify import notify
+notify("text here", channel="project-myproject")
+
+

This will only work if the App has been added to the specified channel.

+

The following syntax can be used to upload a file:

+
bussilab notify --message "text here" --file /path/to/file
+
+

or from python:

+
from bussilab.notify import notify
+notify("text here",file="/path/to/file")
+
+

The commands above will return the URL of the message. This URL can be used +later to update or delete them or to post reactions:

+
url=$(bussilab notify --message "text here")
+bussilab notify --update $url --message "revised message"
+bussilab notify --react $url:heart
+
+# this will remove only the reaction:
+bussilab notify --delete $url:heart
+
+# this will remove the entire message:
+bussilab notify --delete $url
+
+url=$(bussilab notify --message "text here")
+
+

or from python:

+
from bussilab.notify import notify
+url=notify("text here")
+notify("revised message", update=url)
+notify(react=url+":heart")
+notify(delete=url+":heart")
+notify(delete=url)
+
+

In these cases, the channel is not needed and should not be provided. +Notice that you will only be able to update or delete messages sent through the +App.

+
+
+
+
+
+
+

Functions

+
+
+def notify(message: str = '', channel: str = None, *, react: str = None, update: str = None, delete: str = None, reply: str = None, reply_broadcast: str = None, title: str = '', screenlog: str = '', screenlog_maxlines: int = 0, footer: bool = True, type: str = 'mrkdwn', file: str = '', token: str = None) +
+
+

Tool to send notifications to Slack.

+

Parameters

+
+
message : str
+
A string that will form the body of the message.
+
channel : None or str
+
The channel. By default, taken from your ~/.bussilabrc +configuration file.
+
update : None or str
+
The URL of a message to be updated.
+
delete : None or str
+
The URL of a message to be deleted. By passing a URL +concatenated with the string ":name_of_reaction" you can +delete a reaction. Buy passing two comma-separated URLs +you can delete both a file and the message with which it was +shared.
+
reply : None or str
+
The URL of a message to be replied
+
reply_broadcast : None or str
+
The URL of a message to be broadcast-replied
+
react : None or str
+
The URL of a message to which you want to add a reaction, +followed by the string :name_of_the_reaction
+
file : None or str
+
The path of a file to be uploaded
+
title : str
+
The title of the notification.
+
footer : bool
+
If True, a footer is added with current user, machine, and +directory.
+
type : str
+
The type of message. Can be "mrkdwn" or "plain_text".
+
token : None or str
+
The token. By default, taken from your ~/.bussilabrc +configuration file.
+
+

Returns

+
str
+    A string with the URL of the sent message.
+    In case the <code>delete</code> keyword is used, it returns an empty
+    string.
+    In case a file is uploaded, it returns two comma-separated
+    URLs corresponding to the message and to the file.
+
+

Example

+
from bussilab.notify import notify
+notify("send this message")
+
+

See bussilab.notify for more examples.

+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/pip.html b/bussilab/pip.html new file mode 100644 index 0000000..345044b --- /dev/null +++ b/bussilab/pip.html @@ -0,0 +1,102 @@ + + + + + + +bussilab.pip API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.pip

+
+
+

Module implementing a small tool for installing and updating packages with pip.

+
+
+
+
+
+
+

Functions

+
+
+def install(packages: Union[str, List[str]], *, upgrade: bool = False, user: bool = False, timeout: Optional[int] = None) +
+
+

Install one or more packages with pip.

+

Install packages making sure they get installed with the currently used +python interpreter.

+

Parameters

+
+
packages : str or list
+
Package to be installed/upgraded. If a list is passed, multiple +packages are installed/upgraded.
+
upgrade : bool, optional
+
if True, run pip with --upgrade.
+
user : bool, optional
+
if True, run pip with --user.
+
+
+
+def upgrade_all(user: bool = False, *, timeout: Optional[int] = None) +
+
+

Upgrade all installed packages using pip.

+

Warning: it assumes all available packages are installed with pip.

+

Parameters

+
+
user : bool, optional
+
if True, install/upgrade packages in with --user option.
+
+
+
+def upgrade_self(*, user: bool = False, timeout: Optional[int] = None) +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/potts.html b/bussilab/potts.html new file mode 100644 index 0000000..915e56b --- /dev/null +++ b/bussilab/potts.html @@ -0,0 +1,351 @@ + + + + + + +bussilab.potts API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.potts

+
+
+

Module containing a tool to solve Potts models by enumeration

+

See Model.

+
+
+
+
+
+
+
+
+

Classes

+
+
+class InferResult +(*, h: numpy.ndarray, J: numpy.ndarray, averages: numpy.ndarray, loglike: float, success: bool, message: str, nfev: int, nit: int) +
+
+

Result of a Model.infer() calculation.

+
+ +Expand source code + +
class InferResult(coretools.Result):
+    """Result of a `bussilab.potts.Model.infer` calculation."""
+    def __init__(self,
+                 *,
+                 h: np.ndarray,
+                 J: np.ndarray,
+                 averages: np.ndarray,
+                 loglike: float,
+                 success: bool,
+                 message: str,
+                 nfev: int,
+                 nit: int):
+        super().__init__()
+        self.h = h
+        """`np.ndarray`, optimized h."""
+        self.J = J
+        """`np.ndarray`, optimized h."""
+        self.averages = averages
+        """`np.ndarray`, resulting averages."""
+        self.loglike = loglike
+        """`float` containing the resulting likelihood Gamma."""
+        self.success = success
+        """`bool` reporting the success of the minimizer."""
+        self.message = message
+        """`str` reporting the possible reason of failuer of the minimizer."""
+        self.nfev = nfev
+        """`int` reporting the number of function evaluations."""
+        self.nit = nit
+        """`int` reporting the number of iterations in the minimization procedure."""
+
+

Ancestors

+ +

Instance variables

+
+
var J
+
+

np.ndarray, optimized h.

+
+
var averages
+
+

np.ndarray, resulting averages.

+
+
var h
+
+

np.ndarray, optimized h.

+
+
var loglike
+
+

float containing the resulting likelihood Gamma.

+
+
var message
+
+

str reporting the possible reason of failuer of the minimizer.

+
+
var nfev
+
+

int reporting the number of function evaluations.

+
+
var nit
+
+

int reporting the number of iterations in the minimization procedure.

+
+
var success
+
+

bool reporting the success of the minimizer.

+
+
+
+
+class Model +(size: int, colors: int = 1, shifted: bool = False, fullmatrix: bool = True) +
+
+

Init model. +size: number of spins +colors: number of colors +fullmatrix: set to False to use less memory (slower)

+
+ +Expand source code + +
class Model:
+    def __init__(self,
+                 size: int,
+                 colors: int = 1,
+                 shifted: bool = False,
+                 fullmatrix: bool = True):
+        """Init model.
+           size: number of spins
+           colors: number of colors
+           fullmatrix: set to False to use less memory (slower)
+        """
+        if colors != 1:
+            warnings.warn("number of colors different from 1 is not tested")
+        if shifted:
+            warnings.warn("shifted spins not tested")
+        self.size=size
+        self.colors=colors
+        self.nstates=(1+colors)**self.size
+        # list of all possible sequences
+        self.allseq=_make_lists(self.size,colors,shifted=shifted)
+        # outer products of all possible sequences
+        # used to compute the energy
+        # takes a lot of memory but allow to write operations with numpy
+        if fullmatrix:
+            self.allseq_matrix=np.einsum('ki,kj->kij',self.allseq,self.allseq)
+        else:
+            self.allseq_matrix=None
+    def compute(self,
+                h: np.ndarray,
+                J: np.ndarray):
+        """Compute averages <sigma_i,sigma_j> for a coupling matrix J.
+           Returns (a,b) with a=free energy and b=averages
+        """
+        if not self.allseq_matrix is None:
+            all_ene=np.tensordot(self.allseq_matrix,self.fixJ(J),((1,2),(0,1)))
+        else:
+            all_ene=np.einsum("ki,kj,ij->k",self.allseq,self.allseq,self.fixJ(J))
+        if h is not None:
+            all_ene+=np.matmul(self.allseq,h.T)
+        shift=all_ene.min()
+        all_ene-=shift
+        prob=np.exp(-all_ene)
+        Z=np.sum(prob)
+        if self.allseq_matrix is not None:
+            average=np.tensordot(prob,self.allseq_matrix,(0,0))/Z
+        else:
+            average=np.einsum("ki,kj,k->ij",self.allseq,self.allseq,prob)/Z
+        return (-np.log(Z)+shift,average)
+    def loglike(self,
+                h: np.ndarray,
+                J: np.ndarray,
+                ave: np.ndarray):
+        """Compute -log likelihood for a coupling matrix J with averages ave.
+           Returns (a,b) with a=-log likelihood and b=derivatives
+        """
+        c=self.compute(h,self.fixJ(J))
+        l=np.sum(self.fixJ(J)*ave)
+        if h is not None:
+            l+=np.sum(h*np.diag(ave))
+        der=-c[1]+ave
+        return (l-c[0],der)
+    def draw(self,
+             h: np.ndarray,
+             J: np.ndarray,
+             n: int):
+        """Compute averages for a coupling matrix J sampling n states.
+        """
+        if self.allseq_matrix is not None:
+            all_ene=np.tensordot(self.allseq_matrix,self.fixJ(J),((1,2),(0,1)))
+        else:
+            all_ene=np.einsum("ki,kj,ij->k",self.allseq,self.allseq,self.fixJ(J))
+        if h is not None:
+            all_ene+=np.matmul(self.allseq,h.T)
+        shift=all_ene.min()
+        all_ene-=shift
+        prob=np.exp(-all_ene)
+        Z=np.sum(prob)
+        prob/=Z
+        ret=np.zeros((self.size*self.colors,self.size*self.colors))
+        for i in range(n):
+            j=np.random.choice(len(self.allseq),p=prob)
+            if self.allseq_matrix is not None:
+                ret+=self.allseq_matrix[j]
+            else:
+                ret+=np.outer(self.allseq[j],self.allseq[j])
+        return ret/n
+    def fixJ(self,
+             J: np.ndarray):
+        newJ=0.5*(J+J.T)
+        for i in range(self.size):
+            newJ[self.colors*i:self.colors*(i+1),self.colors*i:self.colors*(i+1)]=0.0
+        return newJ
+    def infer(self,
+              averages: np.ndarray,
+              nseq: int = 1,
+              reg: Optional[Callable] = None):
+        x0=np.zeros(self.size*self.size*self.colors*self.colors)
+        def function(par,m,a):
+            J=m.fixJ(par.reshape((self.size*self.colors,self.size*self.colors)))
+            h=np.diag(par.reshape((self.size*self.colors,self.size*self.colors)))
+            c=m.loglike(h,J,a)
+            c=(nseq*c[0],nseq*c[1])
+            if reg is not None:
+                r=reg(J)
+                c=(c[0]+r[0],c[1]+r[1])
+            return (c[0],c[1].flatten())
+        res = minimize(function, x0, args=(self,averages),
+              method="L-BFGS-B",jac=True,tol=1e-10)
+        h=np.diag(res.x.reshape((self.size*self.colors,self.size*self.colors)))
+        J=self.fixJ(res.x.reshape((self.size*self.colors,self.size*self.colors)))
+        return InferResult(
+            h=h,
+            J=J,
+            averages=averages,
+            loglike=res.fun,
+            success=res.success,
+            message=res.message,
+            nfev=res.nfev,
+            nit=res.nit
+            )
+    def random_couplings(self,
+                         seed: Optional[int] = None):
+        if seed is not None:
+            np.random.seed(seed)
+        J=np.triu(np.random.normal(0,1.0,(self.size*self.colors,self.size*self.colors)))
+        return self.fixJ(J)
+
+

Methods

+
+
+def compute(self, h: numpy.ndarray, J: numpy.ndarray) +
+
+

Compute averages for a coupling matrix J. +Returns (a,b) with a=free energy and b=averages

+
+
+def draw(self, h: numpy.ndarray, J: numpy.ndarray, n: int) +
+
+

Compute averages for a coupling matrix J sampling n states.

+
+
+def fixJ(self, J: numpy.ndarray) +
+
+
+
+
+def infer(self, averages: numpy.ndarray, nseq: int = 1, reg: Optional[Callable] = None) +
+
+
+
+
+def loglike(self, h: numpy.ndarray, J: numpy.ndarray, ave: numpy.ndarray) +
+
+

Compute -log likelihood for a coupling matrix J with averages ave. +Returns (a,b) with a=-log likelihood and b=derivatives

+
+
+def random_couplings(self, seed: Optional[int] = None) +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/reports.html b/bussilab/reports.html new file mode 100644 index 0000000..d62ec72 --- /dev/null +++ b/bussilab/reports.html @@ -0,0 +1,69 @@ + + + + + + +bussilab.reports API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.reports

+
+
+
+
+
+
+
+
+

Functions

+
+
+def workstations(wks: Optional[List] = None, short: bool = True) +
+
+
+
+
+
+
+
+
+ +
+ + + diff --git a/bussilab/wham.html b/bussilab/wham.html new file mode 100644 index 0000000..13a2b60 --- /dev/null +++ b/bussilab/wham.html @@ -0,0 +1,277 @@ + + + + + + +bussilab.wham API documentation + + + + + + + + + + + +
+
+
+

Module bussilab.wham

+
+
+

Module containing a WHAM implementation.

+

See wham().

+
+
+
+
+
+
+

Functions

+
+
+def wham(bias, *, frame_weight=None, traj_weight=None, T: float = 1.0, maxiter: int = 1000, threshold: float = 1e-20, verbose: bool = False, logZ: Optional[numpy.ndarray] = None, logW: Optional[numpy.ndarray] = None, normalize: Union[bool, str] = 'log', method: str = 'minimize', minimize_opt: Optional[dict] = None) +
+
+

Compute weights according to binless WHAM.

+

The main input for this calculation is in the 2D array bias. +Element bias[i, j] should contain the energy of the i-th frame computed +according to the j-th Hamiltonian. Trajectories should be concatenated first, +so that the total number of frames should be equal to the number of frames +of each trajectory multiplied by the number of trajectories. +However, it is also possible to contatenate simulations of different lengths. +It is crucial however to compute the potential according to each of the employed +Hamiltonian on all the frames, not only on those simulated using that Hamiltonian.

+

Notice that by default weights are normalized. It is possible to override this behavior with +normalize=False. However, starting with v0.0.40, this should not be necessary. The new +implementation of normalization should be numerically stable in all cases.

+

Bugs

+

Up to version 0.042, method="minimize" does not work correctly when setting traj_weights. +As a consequence, results produced with v0.0.41, where this method is the default, +might be incorrect. In v0.0.42 this is temporarily fixed by reverting to method="substitute" +when using traj_weights. In v0.0.43 this should be finally fixed: both methods should +equally work in all cases, and the default "minimize" method should require less iterations.

+

Combining Trajectories Of Different Length

+

Let's imagine three frames obtained from three Hamiltonians. Let's assume that the +energy of frame i in Hamiltonian j is given by bias[i, j] defined as

+
import numpy as np
+bias = np.array([[1, 10, 7],
+                [2, 9, 6],
+                [3, 8, 5]])
+
+

We can compute the weights with the following command:

+
np.exp(wham.wham(bias).logW)
+
+array([0.41728571, 0.39684866, 0.18586563])
+
+

We now notice that the second and third columns of this matrix are equal except for +a rigid shift. +They thus correspond to Hamiltonians that are equivalent. +We should have been able to obtain the same result saying that these frames were +coming from two simulations. If we only pass the first two columns however +we obtain different weights

+
np.exp(wham.wham(bias[:, 0:2]).logW)
+
+array([0.28224026, 0.43551948, 0.28224026])
+
+

In order to correcly analyze these frames we should pass the information that +the second Hamiltonian was used for twice the time:

+
np.exp(wham.wham(bias[:, 0:2], traj_weight=(1, 2)).logW)
+
+array([0.41728571, 0.39684866, 0.18586563])
+
+

Notice that now the weights are identical to those computed in the first example.

+

Trusting More A Trajectory Than Another

+

When you concatenate trajectories, you might explicitly want to trust more a trajectory +than another. +For instance, two trajectories might have been accumulated with a different +stride, and the reliability of each frame of the one with smaller stride should be lower. +We thus would like to assign a weight to each frame that accounts for its reliability.

+

Consider the following command:

+
import numpy as np
+np.exp(wham.wham([[3, 5],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4],
+                  [4, 4]]).logW)
+
+

that results in the following weights

+
array([0.06421006, 0.09357899, 0.09357899, 0.09357899, 0.09357899,
+       0.09357899, 0.09357899, 0.09357899, 0.09357899, 0.09357899,
+       0.09357899])
+
+

Notice that all the frames except for the first one are identical. An equivalent result +would have been obtained using

+
import numpy as np
+np.exp(wham.wham([[3, 5],
+                  [4, 4]], frame_weight=(1, 10)).logW)
+
+array([0.06421006, 0.93578994])
+
+

Clearly, the weight of the second frame in this example is equal to ten times the +weights of the ten corresponding frames in the previous example.

+

Parameters

+
+
bias : np.ndarray
+
An array with shape (nframes, ntraj) containing the bias potential applied to +each frame according to each of the Hamiltonians.
+
frame_weight : np.ndarray, optional
+
An array with nframes elements. These elements should contain the reliability weight +of the frames. +By default, these weights are set to one.
+
traj_weight : np.ndarray, optional
+
An array with ntraj elements. These elements should contain the total weight of each of +the Hamiltonians. Should be used when combining trajectories of different lengths.
+
T : float, optional
+
The temperature of the system. This number is just used to divide the bias array in +order to make it adimensional. In case replicas are simulated at different temperatures, +it is possible to pass an array here, with ntraj elements.
+
maxiter : int, optional
+
Maximum number of iterations in the minimization procedure.
+
threshold : float, optional
+
Threshold for the minimization procedure.
+
verbose : bool, optional
+
If True, print information as the minimization proceeds.
+
logZ : np.ndarray, optional
+
Array with ntraj elements. +Initial value for the logarithm of the partition functions. If not provided, it is +computed from the bias. +Providing an initial guess that is close to the converged +value (e.g. as obtained from a calculation with a limited number of frames) can speed up +significantly the convergence.
+
logW : np.ndarray, optional
+
Array with nframes elements. +Initial value for the logarithm of the weights. If not provided, they are computed from +the bias. +Providing an initial guess that is close to the converged value can speed up +significantly the convergence. If logW is provided, logZ is ignored.
+
normalize : bool or str, optional
+
By default, "log", which properly normalizes weights in all cases. +normalize=True or False is enabled for backward compatibility.
+
method : str, optional
+
If "substitute", solve self-consistent equations by substitution. +If "minimize", use a minimization as in J Chem Phys 136, 144102 (2012). +Prior to version 0.0.40, the default was "substitute". +Starting with version 0.0.41, the default is "minimize".
+
minimize_opt : dict, optional
+
If method=="minimize", this dict can be used to pass options to scipy.minimize. +Notice that by default the minimization is performed using 'L-BFGS-B'.
+
+
+
+
+
+

Classes

+
+
+class WhamResult +(*, logW: numpy.ndarray, logZ: numpy.ndarray, nit: int, nfev: int, eps: float) +
+
+

Result of a wham() calculation.

+
+ +Expand source code + +
class WhamResult(coretools.Result):
+    """Result of a `bussilab.wham.wham` calculation."""
+    def __init__(self,
+                 *,
+                 logW: np.ndarray,
+                 logZ: np.ndarray,
+                 nit: int,
+                 nfev: int,
+                 eps: float):
+        super().__init__()
+        self.logW = logW
+        """`numpy.ndarray` containing the logarithm of the weight of the frames."""
+        self.logZ = logZ
+        """`numpy.ndarray` containing the logarithm of the partition function of each state."""
+        self.nit = nit
+        """The number of performed iterations."""
+        self.nfev = nfev
+        """The number of function evalutations (might differ from nit when using method='minimize')."""
+        self.eps = eps
+        """The final error in the iterative solution."""
+
+

Ancestors

+ +

Instance variables

+
+
var eps
+
+

The final error in the iterative solution.

+
+
var logW
+
+

numpy.ndarray containing the logarithm of the weight of the frames.

+
+
var logZ
+
+

numpy.ndarray containing the logarithm of the partition function of each state.

+
+
var nfev
+
+

The number of function evalutations (might differ from nit when using method='minimize').

+
+
var nit
+
+

The number of performed iterations.

+
+
+
+
+
+
+ +
+ + + diff --git a/examples/MaxEnt.html b/examples/MaxEnt.html new file mode 100644 index 0000000..092f573 --- /dev/null +++ b/examples/MaxEnt.html @@ -0,0 +1,7865 @@ + + + + + +MaxEnt + + + + + + + + + + + + +
+
+ + diff --git a/examples/example_ann.html b/examples/example_ann.html new file mode 100644 index 0000000..5e8c25b --- /dev/null +++ b/examples/example_ann.html @@ -0,0 +1,10214 @@ + + + + + +example_ann + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/examples/example_lohman.html b/examples/example_lohman.html new file mode 100644 index 0000000..8e96aa6 --- /dev/null +++ b/examples/example_lohman.html @@ -0,0 +1,7639 @@ + + + + + +example_lohman + + + + + + + + + + + + +
+
+ + diff --git a/examples/example_potts.html b/examples/example_potts.html new file mode 100644 index 0000000..402213b --- /dev/null +++ b/examples/example_potts.html @@ -0,0 +1,7725 @@ + + + + + +example_potts + + + + + + + + + + + + +
+
+ + diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 0000000..3ef9844 --- /dev/null +++ b/examples/index.html @@ -0,0 +1,42 @@ + + + + + + + Directory Tree + + + +

Directory Tree

+ .
+ ├── MaxEnt.html
+ ├── example_ann.html
+ ├── example_lohman.html
+ ├── example_potts.html
+ └── index.html
+


+

+ tree v2.0.2 © 1996 - 2022 by Steve Baker and Thomas Moore
+ HTML output hacked and copyleft © 1998 by Francesc Rocher
+ JSON output hacked and copyleft © 2014 by Florian Sesser
+ Charsets / OS/2 support © 2001 by Kyosuke Tokoro +

+ + diff --git a/index.html b/index.html new file mode 100644 index 0000000..e7a1ecb --- /dev/null +++ b/index.html @@ -0,0 +1,10 @@ + + + +Page Auto Redirect + + + +This is an auto redirect page. + +