diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 520db657d549175feb23856dc0a8f1008c8c8e47..51a0a266913005d1f29b928f99fa91186c32a139 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,18 +1,50 @@
-before_script:
-  - apt-get update
-  # uncomment first time
-  #- rm -rf TestFiles
-  #- git submodule update --init
-  #- git submodule sync
-  #- git submodule update
-
+image: dtuwindenergy/wetb
 
 test-3.4:
-  image: mmpe/wetb
+  stage:  
+    test
+#  except:
+#    - test_pypi
   script:
-  #- python3 setup.py test
+  - apt-get update
   - pip3 install pytest
   - pip3 install mock
   - python3 -m pytest --cov=wetb
   tags:
   - python
+
+  # ===== BUILD WHEELS AND UPLOAD TO PYPI =====
+pypi_linux:
+  stage:  
+    deploy
+  only:
+    - tags
+    - test_pypi
+  script:
+    - apt-get update
+    - pip install -e . --upgrade
+    - python3 -c 'from git_utils import write_vers; write_vers()'
+    - python3 -m pip install -U setuptools wheel
+    - python3 setup.py sdist bdist_wheel
+    - python3 -m pip install -U twine
+    - python3 -c 'from git_utils import rename_dist_file; rename_dist_file()'
+    - twine upload dist/* -u $TWINE_USERNAME -p $TWINE_PASSWORD
+    #- twine upload --repository-url https://test.pypi.org/legacy/ dist/* -u $TWINE_USERNAME -p $TWINE_PASSWORD # for testing purposes
+  tags:  
+    - python
+
+
+pypi_windows:
+  stage:  
+    deploy
+  only:
+    - tags
+    - test_pypi
+  script:
+    - c:/Anaconda3/envs/WindEnergyToolbox/python.exe -c "from git_utils import write_vers; write_vers()"
+    - c:/Anaconda3/envs/WindEnergyToolbox/python.exe setup.py bdist_wheel
+    - twine upload dist/* -u %TWINE_USERNAME% -p %TWINE_PASSWORD%
+    #- twine upload --repository-url https://test.pypi.org/legacy/ dist/* -u %TWINE_USERNAME% -p %TWINE_PASSWORD% # for testing purposes
+  tags:  
+    - CPAV_old
+
diff --git a/.pypirc b/.pypirc
new file mode 100644
index 0000000000000000000000000000000000000000..bc2d57e7b0d6a95bf91e316fd0fe200cf87afe44
--- /dev/null
+++ b/.pypirc
@@ -0,0 +1,9 @@
+[distutils]
+index-servers=
+    pypi
+    #testpypi # include this line for testing
+
+[testpypi]
+repository: https://test.pypi.org/legacy/ # use this line when testing
+#repository: https://upload.pypi.org/legacy/
+username: DTUWindEnergy
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..3b6639b7fc1705aa84161080abfda6627c581c75
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,17 @@
+FROM continuumio/anaconda3:latest
+MAINTAINER Mikkel Friis-Møller <mikf@dtu.dk>
+
+RUN apt-get update && \
+    apt-get install make && \
+    apt-get install libgl1-mesa-glx -y && \
+    apt-get install gcc gfortran -y
+	
+RUN conda update -y conda && \
+    conda install -y sphinx_rtd_theme && \
+	conda install setuptools_scm future h5py pytables pytest pytest-cov nose sphinx blosc pbr paramiko && \
+	conda install scipy pandas matplotlib cython xlrd coverage xlwt openpyxl psutil pandoc twine pypandoc && \
+	conda install -c conda-forge pyscaffold sshtunnel --no-deps && \
+    conda clean -y --all
+	
+RUN pip install --upgrade pip && \
+	pip install --no-cache-dir git+https://gitlab.windenergy.dtu.dk/toolbox/WindEnergyToolbox.git
diff --git a/docker/Makefile b/docker/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a366cf4a65a2283517ce0ec67c0ad30d448e32eb
--- /dev/null
+++ b/docker/Makefile
@@ -0,0 +1,21 @@
+# build image
+docker build -t dtuwindenergy/wetb ./
+# or pull from docker hub
+  
+# create container
+docker create -it --name wetb dtuwindenergy/wetb
+
+# start container
+docker start wetb
+
+# enter container with bash prompt
+docker exec -it wetb bash
+
+# push
+docker push dtuwindenergy/wetb
+
+#checkout single branch for testing:
+git clone --single-branch --branch test_pypi https://gitlab.windenergy.dtu.dk/toolbox/WindEnergyToolbox.git
+
+#Copy local folder into docker container:
+docker cp "C:\Sandbox\Git\WindEnergyToolbox\." wetb:/WETB/
diff --git a/docs/developer-guide.md b/docs/developer-guide.md
index bb7f1bac05b91032ad891bbcb8af9bbccda842c8..1bca023f531f690b28da501f686b0faf41e30a35 100644
--- a/docs/developer-guide.md
+++ b/docs/developer-guide.md
@@ -262,6 +262,14 @@ To be written
 
 ## Make and upload wheels to PyPi
 
+### Linux
+
+For Linux the wheels are now automatically build and pushed to pypi when creating a tag.
+
+### Windows
+
+For Windows the automated build and push to pypi has not yet been implemented and the developer has to follow the manual procedure outlined below:
+
 Workflow for creating and uploading wheels is as follows:
 
 - Make tag: ```git tag "vX.Y.Z"```, and push tag to remote: ```git push --tags```
diff --git a/git_utils.py b/git_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd34e945d534c123096a7e5a9fd933667974bf74
--- /dev/null
+++ b/git_utils.py
@@ -0,0 +1,95 @@
+'''
+Created on 28. jul. 2017
+
+@author: mmpe
+'''
+import os
+import subprocess
+
+
+def _run_git_cmd(cmd, git_repo_path=None):
+    git_repo_path = git_repo_path or os.getcwd()
+    if not os.path.isdir(os.path.join(git_repo_path, ".git")):
+        raise Warning("'%s' does not appear to be a Git repository." % git_repo_path)
+    try:
+        process = subprocess.Popen(cmd,
+                                   stdout=subprocess.PIPE,
+                                   universal_newlines=True,
+                                   cwd=os.path.abspath(git_repo_path))
+        stdout = process.communicate()[0]
+        if process.returncode != 0:
+            raise EnvironmentError()
+        return stdout.strip()
+
+    except EnvironmentError as e:
+        raise e
+        raise Warning("unable to run git")
+
+
+def get_git_version(git_repo_path=None):
+    cmd = ["git", "describe", "--tags", "--dirty", "--always"]
+    return _run_git_cmd(cmd, git_repo_path)
+
+
+def get_tag(git_repo_path=None):
+    return _run_git_cmd(['git', 'describe', '--tags', '--abbrev=0'], git_repo_path)
+
+
+def set_tag(tag, push, git_repo_path=None):
+    _run_git_cmd(["git", "tag", tag], git_repo_path)
+    if push:
+        _run_git_cmd(["git", "push"], git_repo_path)
+        _run_git_cmd(["git", "push", "--tags"], git_repo_path)
+
+
+def update_git_version(version_module, git_repo_path=None):
+    """Update <version_module>.__version__ to git version"""
+
+    version_str = get_git_version(git_repo_path)
+    assert os.path.isfile(version_module.__file__)
+    with open(version_module.__file__, "w") as fid:
+        fid.write("__version__ = '%s'" % version_str)
+
+    # ensure file is written, closed and ready
+    with open(version_module.__file__) as fid:
+        fid.read()
+    return version_str
+
+def write_vers(vers_file='wetb/__init__.py'):
+    version = get_tag(os.getcwd())
+    print('Writing version: {} in {}'.format(version, vers_file))
+    with open(vers_file, 'r') as f:
+        lines = f.readlines()
+    for n,l in enumerate(lines):
+        if l.startswith('__version__'):
+            lines[n] = "__version__ = '{}'\n".format(version[1:])
+    with open(vers_file, 'w') as f:
+        f.write(''.join(lines))
+		
+def rename_dist_file():
+    for f in os.listdir('dist'):
+        if f.endswith('whl'):
+            split = f.split('linux')
+            new_name = 'manylinux1'.join(split)
+            old_path = os.path.join('dist',f)
+            new_path = os.path.join('dist',new_name)
+            os.rename(old_path, new_path)
+    
+
+def main():
+    """Example of how to run (pytest-friendly)"""
+    if __name__ == '__main__':
+#        pass
+#        import version
+#        import app_utils
+#        git_path = os.path.dirname(app_utils.__file__) + "/../"
+#        update_git_version(version, git_path)
+#        tag = get_tag(os.getcwd())
+#        print(tag)
+#        version = get_git_version(os.getcwd())
+#        print(version)
+#        rename_dist_file()
+        write_vers()
+
+
+main()
diff --git a/setup.cfg b/setup.cfg
index e287a0de26861609e3a471d3983825bffa2209e3..cfc3aa883e1f62ec3e84f88c082ddc7b45197f36 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -8,25 +8,25 @@ home-page = https://gitlab.windenergy.dtu.dk/toolbox/WindEnergyToolbox
 description-file = README
 # Add here all kinds of additional classifiers as defined under
 # https://pypi.python.org/pypi?%3Aaction=list_classifiers
-classifiers = Development Status :: 4 - Beta,
-              Programming Language :: Python,
-              Programming Language :: Python :: 2.7,
-              Programming Language :: Python :: 3,
-              Programming Language :: Python :: 3.3,
-              Programming Language :: Python :: 3.4,
-			  Programming Language :: Python :: 3.5,
-			  Programming Language :: Python :: 3.6,
-              Environment :: Console,
-              Intended Audience :: Education,
-              Intended Audience :: Science/Research,
-              License :: OSI Approved :: GPL License,
-              Operating System :: OS Independent,
-              Operating System :: POSIX :: Linux,
-              Operating System :: Unix,
-              Operating System :: MacOS,
-              Operating System :: Microsoft :: Windows
-              Topic :: Scientific/Engineering :: Mathematics
-
+#classifiers = Development Status :: 4 - Beta,
+#              Programming Language :: Python,
+#              Programming Language :: Python :: 2.7,
+#              Programming Language :: Python :: 3,
+#              Programming Language :: Python :: 3.3,
+#              Programming Language :: Python :: 3.4,
+#			  Programming Language :: Python :: 3.5,
+#			  Programming Language :: Python :: 3.6,
+#              Environment :: Console,
+#              Intended Audience :: Education,
+#              Intended Audience :: Science/Research,
+#              License :: OSI Approved :: GPL License,
+#              Operating System :: OS Independent,
+#              Operating System :: POSIX :: Linux,
+#              Operating System :: Unix,
+#              Operating System :: MacOS,
+#              Operating System :: Microsoft :: Windows
+#              Topic :: Scientific/Engineering :: Mathematics
+#
 [entry_points]
 # Add here console scripts like:
 # console_scripts =
diff --git a/setup.py b/setup.py
index 21fe89c4fe556521732d566f8d8f3d033161db7a..e6bdab939ca67c4dfa6d19cb1422c54a75fb6720 100644
--- a/setup.py
+++ b/setup.py
@@ -2,15 +2,13 @@
 # -*- coding: utf-8 -*-
 """
     Setup file for wetb.
-
-    This file was generated with PyScaffold 2.5, a tool that easily
-    puts up a scaffold for your new Python project. Learn more under:
-    http://pyscaffold.readthedocs.org/
 """
 
 import os
 import sys
-from setuptools import setup
+from setuptools import setup, find_packages
+import wetb
+__version__ = wetb.__version__
 
 try:
     from pypandoc import convert_file
@@ -34,11 +32,13 @@ def setup_package():
 
     needs_sphinx = {'build_sphinx', 'upload_docs'}.intersection(sys.argv)
     sphinx = ['sphinx'] if needs_sphinx else []
-    setup(setup_requires=['six', 'pyscaffold>=2.5a0,<2.6a0'] + sphinx,
+    setup(setup_requires=['six'] + sphinx,
           cmdclass = {'build_ext': build_ext},
           ext_modules = extlist,
-          use_pyscaffold=True,
-          long_description=read_md('README.md'))
+          long_description=read_md('README.md'),
+          version=__version__,
+          packages=find_packages(),
+          )
 
 
 if __name__ == "__main__":
diff --git a/wetb/__init__.py b/wetb/__init__.py
index a4c36dbed94f3e105321a29086a19d6f89cd7a84..c5e546c3f0f961d3a42529146ab5d9329b540326 100644
--- a/wetb/__init__.py
+++ b/wetb/__init__.py
@@ -5,8 +5,9 @@ from __future__ import absolute_import
 from future import standard_library
 standard_library.install_aliases()
 test = "TEST"
-try:
-    import pkg_resources
-    __version__ = pkg_resources.safe_version(pkg_resources.get_distribution(__name__).version)
-except:
-    __version__ = 'unknown'
+__version__ = '0.0.10'
+# try:
+#     import pkg_resources
+#     __version__ = pkg_resources.safe_version(pkg_resources.get_distribution(__name__).version)
+# except:
+#     __version__ = 'unknown'
diff --git a/wetb/standard_models/power_curve.py b/wetb/standard_models/power_curve.py
new file mode 100644
index 0000000000000000000000000000000000000000..1681e28ec4b62ddbdb56994bedfa8eb70af678f7
--- /dev/null
+++ b/wetb/standard_models/power_curve.py
@@ -0,0 +1,104 @@
+import numpy as np
+
+
+def standard_power_curve(power_norm, diameter, turbulence_intensity=.1, shear=(0, 100),
+                         rho=1.225, max_cp=.49,
+                         gear_loss_const=.01, gear_loss_var=.014, generator_loss=0.03, converter_loss=.03):
+    """Generate standard power curve
+
+    The method is extracted from an Excel spreadsheet made by Kenneth Thomsen, DTU Windenergy and
+    ported into python by Mads M. Pedersen, DTU Windenergy.
+
+    Parameters
+    ----------
+    power_norm : int or float
+        Nominal power [kW]
+    diameter : int or float
+        Rotor diameter [m]
+    turbulence_intensity : float
+        Turbulence intensity [%]
+    shear : (power shear coefficient, hub height)
+        Power shear arguments\n
+        - Power shear coeficient, alpha\n
+        - Hub height [m]
+    rho : float optional
+        Density of air [kg/m^3], defualt is 1.225
+    max_cp : float
+        Maximum power coefficient
+    gear_loss_const : float
+        Constant gear loss [%]
+    gear_loss_var : float
+        Variable gear loss [%]
+    generator_loss : float
+        Generator loss [%]
+    converter_loss : float
+
+    Examples
+    --------
+    wsp, power = standard_power_curve(10000, 178.3)
+    plot(wsp, power)
+    show()
+    """
+
+
+    area = (diameter / 2) ** 2 * np.pi
+    wsp_lst = np.arange(0.5, 25, .5)
+    sigma_lst = wsp_lst * turbulence_intensity
+
+    def norm_dist(x, my, sigma):
+        if turbulence_intensity > 0:
+            return 1 / np.sqrt(2 * np.pi * sigma ** 2) * np.exp(-(x - my) ** 2 / (2 * sigma ** 2))
+        else:
+            return x == my
+    p_aero = .5 * rho * area * wsp_lst ** 3 * max_cp / 1000
+
+    # calc power - gear, generator and conv loss
+#     gear_loss = gear_loss_const * power_norm + gear_loss_var * p_aero
+#     p_gear = p_aero - gear_loss
+#     p_gear[p_gear < 0] = 0
+#     gen_loss = generator_loss * p_gear
+#     p_gen = p_gear - gen_loss
+#     converter_loss = converter_loss * p_gen
+#     p_raw = p_gen - converter_loss
+#     p_raw[p_raw > power_norm] = power_norm
+    p_raw = p_aero - power_loss(p_aero, power_norm, gear_loss_const, gear_loss_var, generator_loss, converter_loss)
+
+    powers = []
+    shear_weighted_wsp = []
+    alpha, hub_height = shear
+    r = diameter / 2
+    z = np.linspace(hub_height - r, hub_height + r, 100, endpoint=True)
+    shear_factors = (z / hub_height) ** alpha
+    rotor_width = 2 * np.sqrt(r ** 2 - (hub_height - z) ** 2)
+
+    for wsp, sigma in zip(wsp_lst, sigma_lst):
+        shear_weighted_wsp.append(wsp * (np.trapz(shear_factors ** 3 * rotor_width, z) / (area)) ** (1 / 3))
+        ndist = norm_dist(wsp_lst, wsp, sigma)
+        powers.append((ndist * p_raw).sum() / ndist.sum())
+
+    return wsp_lst, lambda wsp : np.interp(wsp, wsp_lst, powers)
+    return wsp_lst, np.interp(shear_weighted_wsp, wsp_lst, powers)
+
+def power_loss(power_aero, power_norm, gear_loss_const=.01, gear_loss_var=.014, generator_loss=0.03, converter_loss=.03):
+    gear_loss = gear_loss_const * power_norm + gear_loss_var * power_aero
+    p_gear = power_aero - gear_loss
+    p_gear[p_gear < 0] = 0
+    gen_loss = generator_loss * p_gear
+    p_gen = p_gear - gen_loss
+    converter_loss = converter_loss * p_gen
+    p_electric = p_gen - converter_loss
+    p_electric[p_electric > power_norm] = power_norm
+    return power_aero - p_electric
+    
+
+if __name__ == '__main__':
+
+
+    from matplotlib.pyplot import plot, show
+    plot(*standard_power_curve(10000, 178.3, 0., (0, 119), gear_loss_const=.0, gear_loss_var=.0, generator_loss=0.0, converter_loss=.0))
+    plot(*standard_power_curve(10000, 178.3, 0.03, (0, 119), gear_loss_const=.0, gear_loss_var=.0, generator_loss=0.0, converter_loss=.0))
+
+
+
+
+    show()
diff --git a/wetb/utils/cluster_tools/pbsfile.py b/wetb/utils/cluster_tools/pbsfile.py
index 16217c57c392ff16d14d503bb3e25afa438cbf70..10adeacc8987fa3f8d160cfa954032b4bc8a708c 100644
--- a/wetb/utils/cluster_tools/pbsfile.py
+++ b/wetb/utils/cluster_tools/pbsfile.py
@@ -142,7 +142,7 @@ class PBSMultiRunner(PBSFile):
         # find available nodes
         with open(os.environ['PBS_NODEFILE']) as fid:
             files = set([f.strip() for f in fid.readlines() if f.strip() != ''])
-        pbs_files = glob.glob('./**/*.in', recursive=True)
+        pbs_files = [os.path.join(root, f) for root, folders, f_lst in os.walk('.') for f in f_lst if f.endswith('.in')]
 
         # Make a list of [(pbs_in_filename, stdout_filename, walltime),...]
         pat = re.compile(r'[\s\S]*#\s*PBS\s+-o\s+(.*)[\s\S]*(\d\d:\d\d:\d\d)[\s\S]*')
@@ -158,7 +158,7 @@ class PBSMultiRunner(PBSFile):
         # sort wrt walltime
         pbs_info_lst = sorted(pbs_info_lst, key=lambda fow: tuple(map(int, fow[2].split(':'))))[::-1]
         # make dict {node1: pbs_info_lst1, ...} and save
-        d = {f: pbs_info_lst[i::len(files)] for i, f in enumerate(files)}
+        d = dict([(f, pbs_info_lst[i::len(files)]) for i, f in enumerate(files)])
         with open('pbs.dict', 'w') as fid:
             fid.write(str(d))
 
diff --git a/wetb/utils/cluster_tools/ssh_client.py b/wetb/utils/cluster_tools/ssh_client.py
index b729ee85f149ad7e8cf91f003dbd3a54782ba9d3..cc7419f92cccda22aaa99f32891bee7703866393 100644
--- a/wetb/utils/cluster_tools/ssh_client.py
+++ b/wetb/utils/cluster_tools/ssh_client.py
@@ -417,11 +417,10 @@ class SharedSSHClient(SSHClient):
 
 
 if __name__ == "__main__":
-    from mmpe.ui.qt_ui import QtInputUI
-    q = QtInputUI(None)
-    x = None
-    username, password = "mmpe", x.password  # q.get_login("mmpe")
-
-    client = SSHClient(host='gorm', port=22, username=username, password=password)
-    print(client.glob("*.*", ".hawc2launcher/medium1__1__"))
-    #    ssh.upload('../News.txt', 'news.txt')
+    try:
+        import x
+        username, password = 'mmpe', x.password
+        client = SSHClient(host='jess.dtu.dk', port=22, username=username, password=password)
+        print(client.execute("echo hello $USER from $HOSTNAME")[1])
+    except ImportError:
+        x = None
diff --git a/wetb/utils/tests/test_pbs_file.py b/wetb/utils/tests/test_pbs_file.py
index 117a631b9e390778e6558a95bc56706bcb7d871b..b15bcd1c51d70243d199ae368113295b59df678c 100644
--- a/wetb/utils/tests/test_pbs_file.py
+++ b/wetb/utils/tests/test_pbs_file.py
@@ -94,7 +94,7 @@ import re
 # find available nodes
 with open(os.environ['PBS_NODEFILE']) as fid:
     files = set([f.strip() for f in fid.readlines() if f.strip() != ''])
-pbs_files = glob.glob('./**/*.in', recursive=True)
+pbs_files = [os.path.join(root, f) for root, folders, f_lst in os.walk('.') for f in f_lst if f.endswith('.in')]
 
 # Make a list of [(pbs_in_filename, stdout_filename, walltime),...]
 pat = re.compile(r'[\s\S]*#\s*PBS\s+-o\s+(.*)[\s\S]*(\d\d:\d\d:\d\d)[\s\S]*')
@@ -110,7 +110,7 @@ pbs_info_lst = map(get_info, pbs_files)
 # sort wrt walltime
 pbs_info_lst = sorted(pbs_info_lst, key=lambda fow: tuple(map(int, fow[2].split(':'))))[::-1]
 # make dict {node1: pbs_info_lst1, ...} and save
-d = {f: pbs_info_lst[i::len(files)] for i, f in enumerate(files)}
+d = dict([(f, pbs_info_lst[i::len(files)]) for i, f in enumerate(files)])
 with open('pbs.dict', 'w') as fid:
     fid.write(str(d))