Repository: ocelot-collab/ocelot (language: python)

Issue:
wave.py: scan of rect. aperture and compute resulting energies
includes demo/test program


Discussion / hints:

Fix patch:
diff --git a/demos/fel/European_XFEL_performance_estimation.py b/demos/fel/European_XFEL_performance_estimation.py
new file mode 100644
index 00000000..fadfe1ec
--- /dev/null
+++ b/demos/fel/European_XFEL_performance_estimation.py
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Jul 6 15:00:00 2018
+
+@author: sserkez
+"""
+
+import ocelot
+from ocelot.rad.fel import *
+from ocelot import ocelog
+from ocelot.common.globals import *
+import numpy as np
+import matplotlib.pyplot as plt
+from copy import deepcopy
+import matplotlib.colors as colors
+from ocelot.common.math_op import find_nearest_idx
+from ocelot.common.ocelog import ocelog
+from ocelot.rad.undulator_params import *
+
+ocelog.setLevel(logging.ERROR)
+
+#%% Calculation
+cmap = 'terrain'
+class tmp():
+        pass
+
+# E_beam = 7.8 # GeV # CW operation energy
+# E_beam = 17.5 # GeV # maximum
+# E_beam = 14 # GeV # standard
+# E_photon = 10000 # photon energy
+
+dE_beam = 3e-3 # GeV # energy spread
+emit_beam = 0.4 # normalized emittance [mm mrad]
+beta_beam = 30 # average beta function [m]
+I_beam = 5000 # peak current [A]
+t_pulse = 1e-15 # flattop e-beam "duration" [s]
+L_magn = 35*5 # magnetic undulator length [m] (SASE1/2)
+und_duty_factor = 5/(5+1.2) # undulator duty factor
+xlamd = 0.04 # undulator period [m] (SASE1/2)
+
+nharm = 3
+
+method = 'mxie' # Estimation method: {M.Xie} or {Saldin Shneidmiller Yurkov}: 'ssy_opt'
+
+E_beam_arr = np.geomspace(7.5, 17.5, 25)
+E_photon_arr = np.geomspace(3000, 40000, 55) # (SASE1/2)
+
+## uncomment for _SASE3_ parameters
+# L_magn = 35*5 # m (SASE3)
+# xlamd = 0.068 # m (SASE3)
+# E_photon_arr = np.geomspace(250, 3000, 15) # (SASE3)
+
+x_arr = E_photon_arr / 1e3
+y_arr = E_beam_arr
+x_label = '$E_{photon}$ [keV]'
+y_label = '$E_{beam}$ [GeV]'
+xlim = [np.amin(x_arr), np.amax(x_arr)]
+ylim = [np.amin(y_arr), np.amax(y_arr)]
+
+arr = np.zeros((len(y_arr), len(x_arr)))
+K_arr = deepcopy(arr)
+P_Lmagn_arr = deepcopy(arr)
+P_sat = deepcopy(arr)
+sat_power_arr = deepcopy(arr)
+beta_arr = deepcopy(arr)
+coherence = deepcopy(arr)
+medium_accuracy_arr = deepcopy(arr)
+phen_arr = deepcopy(arr)
+beam_power_arr = deepcopy(arr)
+rho_arr = deepcopy(arr)
+lg3d_arr = deepcopy(arr)
+z_sat_magn_arr = deepcopy(arr)
+aw_arr = deepcopy(arr)
+beta_arr = deepcopy(arr)
+N_phot_arr = deepcopy(arr)
+
+
+# for xi in [0]:
+#     for yi in [0]:
+for xi, E_photon in enumerate(E_photon_arr):
+    for yi, E_beam in enumerate(E_beam_arr):
+        
+        xlamds = eV2lambda(E_photon)
+        
+        gamma = E_beam / m_e_GeV
+        delgam = dE_beam / m_e_GeV
+        aw = np.sqrt(2 * gamma**2 * xlamds / xlamd - 1)
+        K_arr[yi, xi] = aw * np.sqrt(2)
+        
+        tmp.aw0 = aw        
+        tmp.iwityp = 0 # 0 only!!! 1 = helical, 0 = planar
+        
+        tmp.curpeak = I_beam
+        tmp.gamma0 = gamma
+        tmp.delgam = delgam
+        tmp.xlamd = xlamd
+        
+        tmp.emitx = emit_beam * 1e-6
+        tmp.emity = emit_beam * 1e-6
+        tmp.betax = beta_beam
+        tmp.betay = beta_beam
+        tmp.Lg_mult = 1 # empirical lain length multiplication parameter
+        tmp.P_mult = 0.5 # empirical saturation power multiplication parameter
+        
+        tmp.hn = nharm # harmonic number for harmonic lasing
+        tmp.qf = 1 # quantun fluctuation effects
+        
+        fel = calculateFelParameters(tmp, method=method)
+        
+        # if fel.delta_q >= 1:
+        #     print(fel.delta_q)
+        #     print(fel.phenh)
+        # fel.beta_opt(apply=1, method=fel.method) # calculate optimal beta function (time consuming if method is "mxie", "ssy_opt" automatically assumes optimal beta)
+        
+        phen_arr[yi, xi] = fel.phenh
+        beam_power_arr[yi, xi] = fel.Pb
+        rho_arr[yi, xi] = fel.rho3
+        lg3d_arr[yi, xi] = fel.lg3
+        
+        en = 2 * np.pi * (fel.emitx+fel.emity) / 2 / fel.lambda0 / fel.gamma0
+        coherence[yi, xi] = 1.1 * en**(1/4) / (1+0.15*en**(9/4))
+        # coherence[yi, xi] = (np.log(fel.Nc/en)/4/en)**2
+        
+        z_sat_magn_arr[yi, xi] = fel.z_sat_magn
+        P_Lmagn_arr[yi, xi] = fel.P(L_magn)
+        P_sat[yi, xi] = fel.P()
+        sat_power_arr[yi, xi] = fel.P(fel.z_sat_magn)
+        beta_arr[yi, xi] = np.mean([fel.betax, fel.betay])
+        medium_accuracy_arr[yi,xi] = fel.inaccurate
+
+x_arr *= nharm
+xlim[0] *= nharm
+xlim[1] *= nharm
+
+P_arr = P_Lmagn_arr # power at saturation limited by undulator magnetic length
+# P_arr = P_sat #power at saturation if unlimited undulator is available
+
+P_arr[np.isnan(P_arr)] = 0
+E_arr = P_arr * t_pulse * 0.5
+N_phot =  E_arr / q_e / phen_arr
+
+
+# printFelParameters(fel)   
+# print('z = {:.2f}, P={:.2f}'.format(fel.z_sat_magn / 0.8, fel.P() / 1e9))
+# plt.figure(5000)
+# plt.scatter(fel.z_sat_magn / 0.8, fel.P() / 1e9)
+# plt.xlim(xmin=0)
+# plt.show()
+
+#%% Plotting
+
+## Available range of K parameter
+K_avail = np.logical_and(K_arr > 1.65, K_arr < 3.9) #current SASE12
+# K_avail = np.logical_and(K_arr > 1.3, K_arr < 3.9) #extended SASE12
+# K_avail = np.logical_and(K_arr > 4, K_arr < 9) #current SASE3
+# K_avail = np.logical_and(K_arr > 1.0, K_arr < 2.5) #SCU18
+# K_avail = np.logical_and(K_arr > 1.0, K_arr < 2.7) #SCU20
+# K_avail = np.logical_and(K_arr > 1.0, K_arr < 10) #SCU40
+# K_avail = np.ones_like(K_avail)
+
+
+plt.figure('Z_sat')
+plt.clf()
+plt.title('Saturation length (physical) [m]')
+plt.pcolormesh(x_arr, y_arr, (z_sat_magn_arr / und_duty_factor) * K_avail, cmap=cmap, vmin=0)#, vmax=L_magn / und_duty_factor * 2)
+plt.colorbar()
+
+if np.any(z_sat_magn_arr / L_magn < 1) and np.any(z_sat_magn_arr / L_magn > 1):
+    cs = plt.contour(x_arr, y_arr, z_sat_magn_arr / L_magn, [1], colors='r')
+    plt.clabel(cs, inline=1, fontsize=10, fmt=' undulator {} m'.format(L_magn/und_duty_factor))
+    
+plt.xlim(xlim)
+plt.ylim(ylim)
+plt.xlabel(x_label)
+plt.ylabel(y_label)
+
+
+plt.figure('Energy')
+plt.clf()
+plt.title('Power at saturation [uJ/fs]')
+plt.pcolormesh(x_arr, y_arr, E_arr*1e6 * K_avail, cmap=cmap)#, norm=colors.LogNorm())#vmin=1e8, vmax=1e12
+plt.colorbar()
+plt.xlim(xlim)
+plt.ylim(ylim)
+plt.xlabel(x_label)
+plt.ylabel(y_label)
+
+
+# plt.figure('beta')
+# plt.clf()
+# plt.title('Beta function [m]')
+# plt.pcolormesh(x_arr, y_arr, beta_arr, cmap=cmap, vmin=0, vmax=30)
+# plt.colorbar()
+# plt.xlim(xlim)
+# plt.ylim(ylim)
+# plt.xlabel(x_label)
+# plt.ylabel(y_label)      
+        
+
+# plt.figure('N_phot')
+# plt.clf()
+# plt.title('N_phot [number]')
+# plt.pcolormesh(x_arr, y_arr, N_phot * t_pulse/1e-15 * K_avail, cmap=cmap, norm=colors.LogNorm())#vmin=1e8, vmax=1e12
+# plt.colorbar()
+# plt.xlim(xlim)
+# plt.ylim(ylim)
+# plt.xlabel(x_label)
+# plt.ylabel(y_label)
+
+
+# plt.figure('Power')
+# plt.clf()
+# plt.title('Power at saturation [GW]')
+# plt.pcolormesh(x_arr, y_arr, P_arr/1e9 * K_avail, cmap=cmap)#, norm=colors.LogNorm())#vmin=1e8, vmax=1e12
+# plt.colorbar()
+# plt.xlim(xlim)
+# plt.ylim(ylim)
+# plt.xlabel(x_label)
+# plt.ylabel(y_label)
+
+
+
+# plt.figure('K_avail')
+# plt.clf()
+# plt.title('K available')
+# plt.pcolormesh(x_arr, y_arr, K_avail, cmap=cmap)#, vmin=0, vmax=1)
+# # plt.colorbar()
+# plt.xlim(xlim)
+# plt.ylim(ylim)
+# plt.xlabel(x_label)
+# plt.ylabel(y_label)
+
+
+# plt.figure('accurate')
+# plt.clf()
+# plt.title('High estimation accuracy')
+# plt.pcolormesh(x_arr, y_arr, np.logical_not(medium_accuracy_arr), cmap=cmap)#, vmin=0, vmax=1)
+# # plt.colorbar()
+# plt.xlim(xlim)
+# plt.ylim(ylim)
+# plt.xlabel(x_label)
+# plt.ylabel(y_label)
+
+
+
+plt.show()
\ No newline at end of file
diff --git a/demos/ipython_tutorials/pfs_2_radiation_field.ipynb b/demos/ipython_tutorials/pfs_2_radiation_field.ipynb
index af755828..0cd94068 100644
--- a/demos/ipython_tutorials/pfs_2_radiation_field.ipynb
+++ b/demos/ipython_tutorials/pfs_2_radiation_field.ipynb
@@ -1034,27 +1034,6 @@
     "spectrogram = wigner_smear(wig, sigma_s=0.1e-6)\n",
     "plot_wigner(spectrogram, figsize=2, plot_proj=0)"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {
diff --git a/demos/ipython_tutorials/pfs_5_SASE_Estimator_and_Imitator.ipynb b/demos/ipython_tutorials/pfs_5_SASE_Estimator_and_Imitator.ipynb
index 8929f785..926d4508 100644
--- a/demos/ipython_tutorials/pfs_5_SASE_Estimator_and_Imitator.ipynb
+++ b/demos/ipython_tutorials/pfs_5_SASE_Estimator_and_Imitator.ipynb
@@ -105,7 +105,7 @@
     }
    ],
    "source": [
-    "beam = generate_beam(E=20.0, dE=2.5e-3, I=5000, l_beam=1e-6, emit_n=0.5e-6, beta=40, l_window=3e-6, shape='gaussian', chirp=0.0009)\n",
+    "beam = generate_beam(E=14.0, dE=4e-3, I=5000, l_beam=10e-6, emit_n=0.8e-6, beta=40, l_window=30e-6, shape='gaussian', chirp=0.0009)\n",
     "plot_beam(beam, figsize=2)"
    ]
   },
@@ -130,7 +130,7 @@
     "                    phs_L = 0.0,\n",
     "                    quad_start = 'd')\n",
     "\n",
-    "E_photon=16000\n",
+    "E_photon=8000\n",
     "beta_av=20\n",
     "prepare_el_optics(beam, lat_pkg, E_photon, beta_av, s=None)\n",
     "lat = lat_pkg[0]\n",
@@ -166,8 +166,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "zsat = 73.64\n",
-      "E_pulse_sat = 197.75 uJ\n"
+      "zsat = 79.91\n",
+      "E_pulse_sat = 1145.08 uJ\n"
      ]
     }
    ],
@@ -264,6 +264,26 @@
     "plot_estimator_energy_evo(fel, und_duty_factor=5/6.08)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1.8487131823039674e-10"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "np.trapz(fel.P_sn, fel.s / speed_of_light)"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -277,7 +297,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "metadata": {
     "scrolled": false
    },
@@ -338,14 +358,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 8,
    "metadata": {},
    "outputs": [
     {
      "name": "stderr",
      "output_type": "stream",
      "text": [
-      "[INFO    ] : \u001b[0mplotting radiation field (dfl)\u001b[0m\n"
+      "[INFO    ] \u001b[0mplotting radiation field (dfl)\u001b[0m\n"
      ]
     },
     {
@@ -362,7 +382,7 @@
      "name": "stderr",
      "output_type": "stream",
      "text": [
-      "[INFO    ] : \u001b[0mplotting radiation field (dfl)\u001b[0m\n"
+      "[INFO    ] \u001b[0mplotting radiation field (dfl)\u001b[0m\n"
      ]
     },
     {
diff --git a/demos/ipython_tutorials/pfs_6_spectral_filtering.ipynb b/demos/ipython_tutorials/pfs_6_spectral_filtering.ipynb
new file mode 100644
index 00000000..8ebfe146
--- /dev/null
+++ b/demos/ipython_tutorials/pfs_6_spectral_filtering.ipynb
@@ -0,0 +1,257 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "*This notebook was created by Svitozar Serkez. Source and license info is on [GitHub](https://github.com/ocelot-collab/ocelot). August 2019.*"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Tutorial N14: SASE estimation and imitation (unfinished)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "initializing ocelot...\n",
+      "import: module PYFFTW is not installed. Install it to speed up calculation\n",
+      "wave.py: module PYFFTW is not installed. Install it if you want speed up dfl wavefront calculations\n"
+     ]
+    }
+   ],
+   "source": [
+    "import numpy as np\n",
+    "import logging\n",
+    "\n",
+    "import ocelot\n",
+    "from ocelot import *\n",
+    "from ocelot.cpbd.beam import *\n",
+    "from ocelot.rad.fel_estimator import *\n",
+    "from ocelot.gui.beam_plot import *\n",
+    "from ocelot.gui.dfl_plot import *\n",
+    "\n",
+    "#ocelog.setLevel(logging.ERROR)\n",
+    "#ocelog.setLevel(logging.DEBUG)\n",
+    "ocelog.setLevel(logging.INFO)\n",
+    "plt.clf()\n",
+    "#%matplotlib notebook"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[INFO    ] \u001b[0mimitating SASE radiation\u001b[0m\n",
+      "[INFO    ] : \u001b[0mgenerating radiation field of shape (nz,ny,nx): (5, 5, 1000)\u001b[0m\n",
+      "[INFO    ] : \u001b[0mgenerating 1d radiation field imitating SASE\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "E_pohoton = 16000 #central photon energy [eV]\n",
+    "kwargs={'xlamds':(h_eV_s * speed_of_light / E_pohoton), #[m] - central wavelength\n",
+    "        'shape':(5,5,1000),           #(x,y,z) shape of field matrix (reversed) to dfl.fld\n",
+    "        'dgrid':(20e-6,20e-6,20e-6), #(x,y,z) [m] - size of field matrix\n",
+    "        'power_rms':(3e-6,10e-6,1e-6),#(x,y,z) [m] - rms size of the radiation distribution (gaussian)\n",
+    "        'power_center':(0,0,None),     #(x,y,z) [m] - position of the radiation distribution\n",
+    "        'power_angle':(0,0),           #(x,y) [rad] - angle of further radiation propagation\n",
+    "        'power_waistpos':(-5,-15),     #(Z_x,Z_y) [m] downstrean location of the waist of the beam\n",
+    "        'wavelength':None,             #central frequency of the radiation, if different from xlamds\n",
+    "        'zsep':None,                   #distance between slices in z as zsep*xlamds\n",
+    "        'freq_chirp':0,                #dw/dt=[1/fs**2] - requency chirp of the beam around power_center[2]\n",
+    "        #'en_pulse':1e-6,               #total energy or max power of the pulse, use only one\n",
+    "        'power':1e8,\n",
+    "        'rho':1e-4\n",
+    "        }\n",
+    "dfl = imitate_sase_dfl(**kwargs);"
+   ]
+  },
+  {
+   "cell_type": "raw",
+   "metadata": {},
+   "source": [
+    "plot_dfl(dfl, domains = 'st', figsize=2)\n",
+    "plot_dfl(dfl, domains = 'sf', figsize=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[INFO    ] \u001b[0mcalculating Wigner distribution from dfl (on-axis fillament)\u001b[0m\n",
+      "[INFO    ] : \u001b[0mplotting Wigner distribution\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<Figure size 432x288 with 0 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "image/png": "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fexjH2Pp0qUcddRR3HjjjdM+FiFmEi90nWolNN7+zd/xl+el/86FEEKIXRF3pgcgannLW96C61Y/li9/+cucddZZHH300QwMDEy6v+XLl3PMMcdw4IEHkslkWLVqFTfccMO0x3nJJZdw8skn09PTA8DmzZu5+uqrGRgYoKuriwULFvDhD3+Yiy66iLPPPrvtfoeHh1m0aFHNskWLFsUWjS996UscfPDB5HI5fvCDH3DiiSdyxx13sN9++037mISYCUqhRWO8idDwQ7+qrcPjz8uYhBBCiE4gobGL8dOf/pTXv/71Hevvs5/9LLfffjtPPfUUe+yxB9/73vd43etexz333EN3d/eU+hwbG+OKK67gZz/7WbzsiSeeoFwus3z58niZ7/usWrUKCCwyb3rTm2r66evri1///Oc/5+ijj6anp4fBwcGadoODg7Er1yte8Yp4+RlnnMHll1/OL3/5S84555wpHYsQM03kOhX9T2Ok5D1fwxFCCCE6hoTGLGHdunWccMIJDddfffXVHHPMMROW33nnnbzrXe9i5cqVALznPe/hQx/6EPfeey9r1qyZ0liuvPJKlixZwrHHHhsvW7VqFfl8nq1bt9ZYZCLqLTLGmFQLzSGHHMKdd94Zv3/00UcZHx/ngAMOSB2LMQZrFUUrZi/lNlynhooSGkIIIWYfitGYJRxzzDE1GZ/q/9JEBsDLXvYyrrjiCjZv3ozv+1x66aWUy2X233//1PblcplisYjv+3ieR7FYnBDQfckll3D66afXZI5avnw5b3jDG/jIRz7C4OAgvu/zyCOPsHbt2kkd56mnnspVV13FunXrGBkZ4VOf+hRve9vbWLhwIQMDA1xzzTUUi0U8z+Oyyy7jpptu4rjjjpvUPoTYlSiHAqPUxKIxPC6hIYQQYvYhobGLceKJJ9bUqnjrW986rf4++tGPcvjhh/OSl7yEvr4+vva1r/GTn/wkdlt6//vfz/vf//64/VlnnUVXVxeXX345X/jCF+jq6uLSSy+N1z/99NPccMMNnH766RP29d3vfpdSqcTBBx/M4sWLOfnkk9m0adOkxnvIIYfwrW99i1NPPZVly5YxNDTEhRdeCAQi6BOf+AS77747S5cu5fzzz+enP/1p01oajdLoCrGrUPZbZ52SRUMIIcRsxMjtZOexZs0au379+pkexrzlvPPO44YbbuCn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\n",
+      "text/plain": [
+       "<Figure size 972x702 with 3 Axes>"
+      ]
+     },
+     "metadata": {
+      "needs_background": "light"
+     },
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "wig = wigner_dfl(dfl)\n",
+    "plot_wigner(wig, downsample=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<Figure size 648x792 with 3 Axes>"
+      ]
+     },
+     "metadata": {
+      "needs_background": "light"
+     },
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[INFO    ] : : : : \u001b[0mmultiplying dfl by trf\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "E_filt = 16000\n",
+    "dEE_filt = 1e-4\n",
+    "\n",
+    "trf = TransferFunction()\n",
+    "dfl.to_domain('f')\n",
+    "\n",
+    "k0 = 2*np.pi * E_filt / h_eV_s / speed_of_light\n",
+    "delta_k = k0 * dEE_filt\n",
+    "\n",
+    "trf.k = dfl.scale_kz()\n",
+    "trf.tr = np.exp(-(trf.k-k0)**2 / 2 / delta_k**2)\n",
+    "\n",
+    "plot_trf(trf)\n",
+    "\n",
+    "dfl_trf(dfl, trf, 'tr', dump_proj=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[INFO    ] : : : : \u001b[0mmultiplying dfl by trf\u001b[0m\n"
+     ]
+    }
+   ],
+   "source": [
+    "dfl_trf(dfl, trf, 'tr', dump_proj=False)\n",
+    "dfl.to_domain('t')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "[INFO    ] : : : : \u001b[0mcalculating Wigner distribution from dfl (on-axis fillament)\u001b[0m\n",
+      "[INFO    ] : : : : : \u001b[0mplotting Wigner distribution\u001b[0m\n"
+     ]
+    },
+    {
+     "data": {
+      "image/png": "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+h2Y2anA74Bfhw8gj0gfreWiNlp+IiIiIiISlA+BRu8Yi8jWgd6AIhCWrhTYLSJd71iKd3fY2OxY4FHg/wFfibPf6eELQ/f5KI/MT0REREREPpIPgcYzBAd5nxCx/PjQ89zQ87NAJ3BORLovAu+EBnEDYGaHEryPxgvAF6PNfuWc+xBYECO/rlC5REREREQkiqyP0TCzz4b+nBl6PtHMGoAG59wc59wmM/sRcI2ZbQH+DtQD1wL3O+eWAjjnNprZz4Hvmlkr8G+CN+b7OHBa2P6mAk8BjcBPgZnhva2cc6+FFe97wF/M7JfAQ8D+BO+hcUeie2iIiIiIiAxmWQ80CHZfCndP6HkOwXtoANwItAJfA64E1hEMEm6K2Pb7QBtwBTAaWAKc6ZybHZbmEILjNoYC/4hSnr6owzn3dCgQuo7gHcQ3ELwr+A+9vjgRERERkcEoq3cGH+h0Z/DU8kiH7gy+M90Z/CO6M3iQ7gzune4MvrN8eK+T3afuDC6Sunh3Bs+FFg0RkbRks2ImIgNPNi8EiAwk+iaJiIiIiIjvFGiIiIiIiIjv1HVKRKQfqUuGiPhN3UclV+mMJyIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIiIiIivlOgISIikoICAtkugohITivKdgFE+kNAMbWIiIhIv1LtS0REREREfKdAQ0REREREfKdAQ0REREREfKdAQ0REREREfKdAQwYMzQAjIn7SJBIiIunRr6iIiIiIiPhOgYaIiIiIiPhOgYaIiIiIiPhOgYaIiIiIiPhOgYaIiIiIiPhOgYaIiIiIiPhOgYaI+EpTgoqI3zR9uUh+Ksp2AURyjU5oIuI3BeAiMhjpl09ERERERHynQENERERERHynQENERERERHynQENERERERHynQENERERERHynQENEkqaZuUTET5qVS2Rg0jdbRERERER8p0BDRERERER8p0BDRERERER8p0BDRERERER8p0BDRERERER8p0BD/j97dx5nSVXf///1uX2np2doxmYcFnUEVGKQxUAY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\n",
+      "text/plain": [
+       "<Figure size 972x702 with 3 Axes>"
+      ]
+     },
+     "metadata": {
+      "needs_background": "light"
+     },
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "wig = wigner_dfl(dfl)\n",
+    "plot_wigner(wig, downsample=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.7.7"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/demos/mpi/T_run_demo.sh b/demos/mpi/T_run_demo.sh
new file mode 100644
index 00000000..ab0f0b88
--- /dev/null
+++ b/demos/mpi/T_run_demo.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+ 
+# Example job script (demo)
+# Christoph Lechner, European XFEL GmbH
+
+# MpiQueueLauncher class uses command line parameters to override some
+# of these parameters, if needed.
+# Currently applies to partition, nodes, and ntasks-per-node.
+
+#SBATCH --partition=maxwell
+#SBATCH --time=0-23:59:00		# Time limit (0 days, 23h59min)
+
+### BEGIN: requested job parameters
+# Note that if the job cannot be scheduled (for instance because
+# the requested number of nodes is beyond your permissions), the
+# job may wait forever.
+#
+# number of nodes (=machines) requested
+#SBATCH --nodes=1			# Number of nodes
+# Requesting fixed number of processors per node (if a machine has more CPUs, some will remain idle)
+#SBATCH --ntasks-per-node=32		# Number of threads per node
+# memory per node
+#SBATCH --mem 200G			# for most cases, 200GB of RAM is ok
+### END: requested job parameters
+
+#SBATCH --job-name  "queue demo"
+
+# simple demo script => don't use jobout sub-directory, but write to cwd
+#SBATCH --output    demo-%j-%N.out	# File to which STDOUT will be written
+#SBATCH --error     demo-%j-%N.err	# File to which STDERR will be written
+
+#SBATCH --mail-type END			# Type of email notification- BEGIN,END,FAIL,ALL
+# per default email goes to job submitter -> no need to specify email address
+# SBATCH --mail-user jane.doe@desy.de   # Email to which notifications will be sent
+
+# Check if mpirun is available. If not, load the module
+source /etc/profile.d/modules.sh
+if ! [ -x "$(command -v mpirun)" ]; then
+	module load mpi/openmpi-x86_64
+fi
+
+rm flag.finish
+
+NODE=`uname -n`
+sleep 10  # some wait time to demonstrate transitions of job state...
+echo "Hallo from compute node $NODE" > T_run_demo_out.txt
+
+touch flag.finish
diff --git a/demos/mpi/T_run_g2.sh b/demos/mpi/T_run_g2.sh
new file mode 100644
index 00000000..be5c254a
--- /dev/null
+++ b/demos/mpi/T_run_g2.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+ 
+# Example job script for GENESIS2
+# Christoph Lechner, European XFEL GmbH
+
+# MpiQueueLauncher class uses command line parameters to override some
+# of these parameters, if needed.
+# Currently applies to partition, nodes, and ntasks-per-node.
+
+#SBATCH --partition=maxwell
+#SBATCH --time=0-23:59:00		# Time limit (0 days, 23h59min)
+#SBATCH --exclude=max-wn025 # exclude node that doesn't work all the time (2021-02-05)
+
+### BEGIN: requested job parameters
+# Note that if the job cannot be scheduled (for instance because
+# the requested number of nodes is beyond your permissions), the
+# job may wait forever.
+#
+# number of nodes (=machines) requested
+#SBATCH --nodes=2			# Number of nodes
+# Requesting fixed number of processors per node (if a machine has more CPUs, some will remain idle)
+#SBATCH --ntasks-per-node=32		# Number of threads per node
+# memory per node
+#SBATCH --mem 200G			# for most cases, 200GB of RAM is ok
+### END: requested job parameters
+
+#SBATCH --job-name  G2
+#SBATCH --output    jobout/G2-%j-%N.out	# File to which STDOUT will be written
+#SBATCH --error     jobout/G2-%j-%N.err	# File to which STDERR will be written
+#SBATCH --mail-type END			# Type of email notification- BEGIN,END,FAIL,ALL
+# per default email goes to job submitter -> no need to specify email address
+# SBATCH --mail-user jane.doe@desy.de   # Email to which notifications will be sent
+
+# Check if mpirun is available. If not, load the module
+source /etc/profile.d/modules.sh
+if ! [ -x "$(command -v mpirun)" ]; then
+	module load mpi/openmpi-x86_64
+fi
+
+# these files can be used to signal the status of the simulation to other processes
+rm -rf flag.start flag.finish
+
+# when your simulations are crashing, a coredump can be useful
+# ulimit -c unlimited
+
+# launch the job
+touch flag.start
+mpirun /gpfs/exfel/data/group/wp72/_code/products/genesis/genesis < tmp.cmd
+touch flag.finish
diff --git a/demos/mpi/demo_MpiQueueLauncher.py b/demos/mpi/demo_MpiQueueLauncher.py
new file mode 100644
index 00000000..ccb08b42
--- /dev/null
+++ b/demos/mpi/demo_MpiQueueLauncher.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3.6
+
+import sys, os
+import matplotlib.pyplot as plt
+from ocelot.utils.xfel_utils import *
+from ocelot.cpbd.magnetic_lattice import MagneticLattice
+from ocelot.gui.genesis_plot import *
+import time
+from ocelot.common.globals import *  #import of constants like "h_eV_s" and "speed_of_light"
+from ocelot.common.py_func import *
+# import logging
+from ocelot import ocelog
+
+ocelog.setLevel(logging.DEBUG)
+
+
+# generate launcher template
+launcher0 = MpiQueueLauncher()
+launcher0.launch_wait=True	# when launch() is called from run_genesis, just submit job, don't wait for results
+launcher0.jobpartition='exfel-wp72'
+# launcher0.jobpartition='maxwell,exfel-wp72' # <== how to specify multiple queues
+launcher0.jobnodes=2
+launcher0.jobntaskspernode=40
+launcher0.jobscript_template='T_run_demo.sh'
+launcher0.dir='.'  # when used with GENESIS v2 adaptor provided by ocelot, this is not needed
+launcher0.jobscript_setup=False # not setting working directory for demo (currently setup procedure still has many GENESIS2 specifics)
+
+# tidy up file that is used by GENESIS v2 job script to signal simulation complete
+os.system('rm -f flag.finish')
+##############
+### DEMO 1 ###
+##############
+# First of all, let's wait for the job to finish
+# This was designed as drop-in replacement of MpiLauncher(), with genesis v2 adapter in mind
+my_launcher = deepcopy(launcher0)
+print('Submitting first job. Only returns once job is complete...')
+my_launcher.launch()
+print('Job completed')
+
+
+# # tidy up file that is used by GENESIS v2 job script to signal simulation complete
+# os.system('rm -f flag.finish')
+# ##############
+# ### DEMO 2 ###
+# ##############
+# another_launcher = deepcopy(launcher0)
+# # This time, we won't wait for job completion (using "submit" instead of "launch").
+# # Ideal for launching and managing multiple jobs.
+# another_launcher.launch_wait=False
+# another_launcher.submit()
+# print('Job was submitted as jobid={}'.format(another_launcher.jobid))
+# print('Waiting for job to finish...')
+# another_launcher.wait_for_completion(verbose=True) # wait for completion (call returns once job complete)
+# print('Job is complete')
+
+
+# # tidy up file that is used by GENESIS v2 job script to signal simulation complete
+# os.system('rm -f flag.finish')
+# ##############
+# ### DEMO 3 ###
+# ##############
+# yet_another_launcher = deepcopy(launcher0)
+# # This time, we won't wait for job completion (using "submit" instead of "launch").
+# # Ideal for launching and managing multiple jobs.
+# yet_another_launcher.launch_wait=False
+# yet_another_launcher.submit()
+# print('Job was submitted as jobid={}'.format(yet_another_launcher.jobid))
+# print('Waiting for job to finish...')
+# while True:
+    # # is job finished?
+    # if yet_another_launcher.is_complete()==True:
+        # break
+    # # no => do some other work
+    # print('doing important stuff in a loop in the demo script, then asking again if job is complete')
+    # time.sleep(12) # <= "important stuff"
+
+# print('Job is complete')
diff --git a/demos/optics/5-SASE_imitator.py b/demos/optics/5-SASE_imitator.py
new file mode 100644
index 00000000..9d816ef9
--- /dev/null
+++ b/demos/optics/5-SASE_imitator.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 28 2021
+@author: sserkez
+"""
+
+import numpy as np
+from ocelot.utils.xfel_utils import *
+from ocelot.gui.genesis_plot import *
+from copy import deepcopy
+
+fntsz = 6
+params = {'image.cmap': def_cmap, 'backend': 'ps', 'axes.labelsize': 3 * fntsz, 'font.size': 3 * fntsz, 'legend.fontsize': 4 * fntsz, 'xtick.labelsize': 4 * fntsz,  'ytick.labelsize': 4 * fntsz, 'text.usetex': False}
+rcParams.update(params)
+
+#%% two pulses
+
+# E_photon = 500 #central photon energy
+# E_photon_range = 40 #photon energy range
+
+# npoints = 700 #points in time domain (more points = wider frequency scale)
+# td_scale = np.linspace(0,9e-6,npoints)
+# td_env = np.zeros_like(td_scale)
+# idx1 = np.logical_and(td_scale>0.5e-6,td_scale<2.5e-6)
+# idx2 = np.logical_and(td_scale>5.5e-6,td_scale<7.5e-6)
+# idx = np.logical_or(idx1,idx2)
+# td_env[idx] = 1
+
+# fd_scale = np.linspace(E_photon-E_photon_range/2, E_photon+E_photon_range/2, npoints) #frequency domain scale (here is it overruled by fit_scale = 'td', so won't change the scale of the output)
+# fd_env = np.exp(-(fd_scale-499)**2 / 1.5**2)
+
+# td_phase2 = np.linspace(0,800,npoints)
+# td_phase1 = np.linspace(0,-800,npoints)
+# td_phase = td_phase2
+# td_phase[0:250] = td_phase1[0:250]
+
+# n_events=10
+#%% Sine
+
+# E_photon = 500 #central photon energy
+# E_photon_range = 40 #photon energy range
+# npoints = 700 #points in time domain (more points = wider frequency scale)
+
+# td_scale = np.linspace(0,16e-6,npoints)
+# td_env = np.ones_like(td_scale)
+
+# fd_scale = np.linspace(E_photon-E_photon_range/2, E_photon+E_photon_range/2, npoints) #frequency domain scale (here is it overruled by fit_scale = 'td', so won't change the scale of the output)
+# fd_env = np.exp(-(fd_scale-499)**2 / 1.5**2)
+
+# td_phase2 = np.linspace(0,800,npoints)
+
+
+# td_phase = np.sin(td_phase2 / 63*1.5) * 63/1.5
+# n_events=10
+#%% Chirped pulse
+
+E_photon = 500 #central photon energy
+E_photon_range = 40 #photon energy range
+
+npoints = 300 #points in time domain (more points = wider frequency scale)
+chirp_val_lin = 100 #abs lin chirp value, arb.units
+# chirp_val_lin = 0 #abs chirp value, arb.units
+
+chirp_val_quad = -100 #abs quad chirp value, arb.units
+# chirp_val_quad = 0 #abs quad chirp value, arb.units
+
+n_events=10 #for statistics, final wigner is averaged
+
+td_scale = np.linspace(0,6e-6,npoints) #time domain scale in um
+td_env = np.ones_like(td_scale) #time domain power envelope, flat-top
+td_env[td_scale<1e-6] = 0
+td_env[td_scale>5e-6] = 0
+
+fd_scale = np.linspace(E_photon-E_photon_range/2, E_photon+E_photon_range/2, npoints) #frequency domain scale (here is it overruled by fit_scale = 'td', so won't change the scale of the output)
+fd_env = np.exp(-(fd_scale-E_photon)**2 / 1.5**2) #instantaneous bandwidth, constant over the pulse
+
+td_phase = np.sign(chirp_val_lin) * np.linspace(-np.abs(chirp_val_lin)**(1/2), np.abs(chirp_val_lin)**(1/2), npoints)**2 #Phase chirp for linear frequency chirp squared
+td_phase += np.sign(chirp_val_quad) * np.linspace(0, np.abs(chirp_val_quad)**(1/4), npoints)**(2+2) #Phase chirp for quadratic frequency chirp squared
+
+#%%
+(td_scale, td, fd_scale, fd) = imitate_1d_sase_like(td_scale, td_env, fd_scale, fd_env, 
+                                                    #td_phase = td_phase, #does not work in fit_scale = 'td'
+                                                    fd_phase = None, phen0 = None, en_pulse = None, 
+                                                    fit_scale = 'td', 
+                                                    n_events = n_events,
+                                                    seed = 1 #This value determines random number generation for stochastic shot noise generation. Change to obtain another ensemble. 
+                                                    )
+
+#td is time domain field, it is a matrix of shape (npoints, nevents), np.abs(td) and np.angle(td) give amplitude and phase
+#td_scale is time domain scale in um
+#fd* is the same, but in the frequency domain
+
+td = td * np.exp(1j * td_phase[:, np.newaxis]) #adding frequency chirp
+## Now td is the complex field in time domain with introduced chirp. Now we ignore frequency domain, as we didn't add the chirp there
+
+#%% the code below is just for plotting
+
+plt.close(100)
+plt.figure(100) #plotting power and phase of 1st event
+plt.clf()
+plt.plot(td_scale * 1e6, np.abs(td[:,0])**2)
+plt.plot(td_scale * 1e6, np.angle(td[:,0]))
+plt.legend(['intensity [arb.units]', 'phase [rad]'])
+plt.xlabel('s [um]')
+plt.show()
+
+
+#%% Wigner averaging
+
+for idx, tdi in enumerate(td.T):
+    wig = WignerDistribution()
+    wig.field = tdi
+    wig.s = td_scale
+    wig.xlamds = (speed_of_light * h_eV_s) / np.mean(fd_scale)
+    wig.z = 0
+    wig.eval()
+    if idx == 0:
+        W = wig.wig
+    else:
+        W += wig.wig
+
+W /= n_events #normalization
+#%% Wigner plotting
+wig_av = deepcopy(wig)
+wig_av.wig = W
+
+plot_wigner(wig_av, figsize=3, x_units='fs', plot_text=0, plot_proj=1, plot_moments=0, fig_name='wigner_averaged', autoscale=0)
diff --git a/demos/optics/6-partially_coherent_radiation_propagation.py b/demos/optics/6-partially_coherent_radiation_propagation.py
new file mode 100644
index 00000000..88b4287c
--- /dev/null
+++ b/demos/optics/6-partially_coherent_radiation_propagation.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jul 12 17:33:00 2021
+
+@author: andrei
+"""
+import numpy as np
+import matplotlib.pyplot as plt
+from ocelot.optics.wave import * # import OCELOT propagation module
+from ocelot.gui.dfl_plot import *  # import plotting routine
+from ocelot.common.globals import *  # import of constants like "h_eV_s" and
+
+ocelog.setLevel(logging.INFO)
+_logger = logging.getLogger(__name__)
+
+n_s = 200 # number of periods in an undulator
+l_w = 0.018 # [m] undulator period 
+L_w = l_w * n_s # undulator length
+
+E_ph = 2167 # resonance energy
+w = E_ph / hr_eV_s 
+xlamds = 2 * np.pi * speed_of_light / w
+
+sigma_r = np.sqrt(2*xlamds*L_w)/4/np.pi #natural radiation size in the waist
+sigma_rp = np.sqrt(xlamds/2/L_w) #natural radiation divergence at the waist
+
+#### #1
+ebeam_sigma_x = 38e-06 # x electron beam size 
+ebeam_sigma_y = 4.68e-06 # y electron beam size
+ebeam_sigma_xp = 25e-06 # x electron beam divergence
+ebeam_sigma_yp = 20e-06 # y electron beam divergence
+
+ebeam_sigma_z = 1 # Electron beam duration. Not physical for the current version of
+                  # SERVAL as here is considered the case of fully monochromatic radiation
+                  # long beam duration corresponds to an infinitesimally small spectral line
+
+N_b = 150 #number of statistical realizations
+Nz, Ny, Nx = N_b, 601, 601 # the shape of the dfl.fld
+
+e_beam_param = 'N_x = {}, '.format(round((ebeam_sigma_x)**2/xlamds/L_w, 3)) + 'N_y = {}, '.format(round((ebeam_sigma_y)**2/xlamds/L_w, 3)) + \
+               'D_x = {}, '.format(round((ebeam_sigma_xp)**2 * L_w/xlamds, 3)) + 'D_y = {}, '.format(round((ebeam_sigma_yp)**2 * L_w/xlamds, 3)) + \
+               'N_b = {} '.format(N_b)
+print(e_beam_param)
+
+Lz, Ly, Lx = ebeam_sigma_z, 300e-6, 400e-6 #size of realspace grid [m]
+dx, dy, dz = Lx / Nx, Ly / Ny, Lz / Nz
+
+# create radiation field
+dfl_SERVAL = RadiationField((N_b, Ny, Nx))  
+dfl_SERVAL.dx, dfl_SERVAL.dy, dfl_SERVAL.dz = dx, dy, dz
+dfl_SERVAL.xlamds = xlamds # SVEA carrieer frequency
+
+dfl_SERVAL.fld = np.random.randn(dfl_SERVAL.Nz(), dfl_SERVAL.Ny(), dfl_SERVAL.Nx()) + 1j * np.random.randn(dfl_SERVAL.Nz(), dfl_SERVAL.Ny(), dfl_SERVAL.Nx()) # Gaussian noise
+
+filePath = 'SERVAL_field'
+dfl_SERVAL.filePath = filePath+'.dfl'
+
+fieldname_SERVAL = '0-at_source_SERVAL'
+dfl_SERVAL = dfl_gen_undulator_serval(dfl_SERVAL, L_w=L_w,
+                                      sig_x=ebeam_sigma_x, sig_y=ebeam_sigma_y,
+                                      sig_xp=ebeam_sigma_xp, sig_yp=ebeam_sigma_yp,
+                                      k_support = 'intensity', s_support='intensity', showfig=False)
+
+plot_dfl(dfl_SERVAL, domains='sf', phase=True, fig_name = fieldname_SERVAL)
+plot_dfl(dfl_SERVAL, domains='kf', phase=True, fig_name = fieldname_SERVAL)
+#%%
+dfl_prop_SERVAL = deepcopy(dfl_SERVAL)
+
+dfl_prop_SERVAL.prop_m(25, m=[15, 20])
+dfl_prop_SERVAL.to_domain(domains='sf') 
+
+fieldname_SERVAL = '1-far_zone_25_m_SERVAL'
+plot_dfl(dfl_prop_SERVAL, domains='sf', phase=True, fig_name = fieldname_SERVAL)
+plot_dfl(dfl_prop_SERVAL, domains='kf', phase=True, fig_name = fieldname_SERVAL)
+#%%
+dfl2_SERVAL = deepcopy(dfl_prop_SERVAL)
+dfl2_SERVAL.to_domain(domains='sf')
+ap_x, ap_y = 1e-3, 1e-3
+dfl_ap_rect(dfl2_SERVAL, ap_x=ap_x, ap_y=ap_y)
+dfl3_SERVAL = deepcopy(dfl2_SERVAL)
+
+f = 25*25/(25+25)
+dfl3_SERVAL.curve_wavefront(r=f)
+dfl3_SERVAL.prop_m(12.5, m=0.25)
+
+fieldname_SERVAL = '3-far_zone_12_5_m_after_aperture_SERVAL'
+plot_dfl(dfl3_SERVAL, domains='sf', phase=True, fig_name = fieldname_SERVAL)
+plot_dfl(dfl3_SERVAL, domains='kf', phase=True, fig_name = fieldname_SERVAL)
+#%%
+dfl4_SERVAL = deepcopy(dfl3_SERVAL)
+m_x, m_y = 0.3, 0.3
+dfl4_SERVAL.prop_m(12.5, m=[m_x, m_y])
+
+fieldname_SERVAL = '4-in_focus_SERVAL'
+plot_dfl(dfl4_SERVAL, domains='sf', phase=True, fig_name = fieldname_SERVAL)
+plot_dfl(dfl4_SERVAL, domains='kf', phase=True, fig_name = fieldname_SERVAL)
+
+
+
diff --git a/demos/optics/7-beamline.py b/demos/optics/7-beamline.py
new file mode 100755
index 00000000..6b1a0f24
--- /dev/null
+++ b/demos/optics/7-beamline.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Feb 11 16:09:20 2021
+
+@author: andrei
+"""
+
+__author__ = "Andrei Trebushinin"
+
+from ocelot.optics.new_wave import *
+from ocelot.gui.dfl_plot import *
+from ocelot.rad.optics_elements import *
+from ocelot.rad.optics_line import *
+from ocelot.rad.transfer_function import *
+from ocelot.rad.propagation import *
+
+ocelog.setLevel(logging.DEBUG)
+
+from ocelot.common.ocelog import *
+_logger = logging.getLogger(__name__)
+
+### defining parameters for gaussian beam 
+E_pohoton = 200 #central photon energy [eV]
+kwargs={'xlamds':(h_eV_s * speed_of_light / E_pohoton), #[m] - central wavelength
+        'rho':1.0e-4, 
+        'shape':(501,501,1),             #(x,y,z) shape of field matrix (reversed) to dfl.fld
+        'dgrid':(400e-5,400e-5,35e-6), #(x,y,z) [m] - size of field matrix
+        'power_rms':(50e-6,50e-6,3e-6),#(x,y,z) [m] - rms size of the radiation distribution (gaussian)
+        'power_center':(0,0,None),     #(x,y,z) [m] - position of the radiation distribution
+        'power_angle':(0,0),           #(x,y) [rad] - angle of further radiation propagation
+        'power_waistpos':(0,0),        #(Z_x,Z_y) [m] downstrean location of the waist of the beam
+        'wavelength':None,             #central frequency of the radiation, if different from xlamds
+        'zsep':None,                   #distance between slices in z as zsep*xlamds
+        'freq_chirp':0,                #dw/dt=[1/fs**2] - requency chirp of the beam around power_center[2]
+        'en_pulse':None,                #total energy or max power of the pulse, use only one
+        'power':1e6,
+        }
+
+l_a, l_b = 100, 10 # sholders of the focusing system
+f = l_a*l_b / (l_a + l_b) #lens focal length
+
+### defining optical elements
+MirrorSurface = ImperfectMirrorSurface(hrms=3e-9, angle=10*np.pi/180, plane='x', eid='MirrorSurface')
+Aperture = ApertureRect(lx=4000e-6, ly=4000e-6, eid='Aperture')
+# Aperture = ApertureEllips(ax=4000e-6, ay=2000e-6, eid='Aperture')
+Lens = ThinLens(fx=f, fy=f, eid='Lens')
+
+FreeSpace_before_lens = FreeSpace(l=l_a - 10, mx=2, my=2, eid='free_space_before_lens')
+FreeSpace_after_aperture = FreeSpace(l=10, eid='free_space_after_aperture')
+FreeSpace_to_the_sample = FreeSpace(l=l_b, mx=0.1, my=0.1, eid='free_space_to_the_sample')
+#%%
+### generation Radiation Field Gaussian beam
+dfl = generate_gaussian_dfl(**kwargs);  #Gaussian beam defenition
+# dfl.to_domain('sf')
+plot_dfl(dfl, domains='s', fig_name='Gaussian beam', phase=True)
+# plot_dfl(dfl, domains='k', fig_name='Gaussian beam', phase=True)
+
+#%%
+line = (FreeSpace_before_lens, Aperture, # set of optical elements
+        FreeSpace_after_aperture, MirrorSurface, Lens, FreeSpace_to_the_sample)
+
+dfl_prop = deepcopy(dfl)
+lat = OpticsLine(line, start=FreeSpace_before_lens, stop=FreeSpace_before_lens) #defining a beamline lattice  with "start" and "stop" elements for propagation
+dfl_prop = propagate(lat, dfl_prop)                
+plot_dfl(dfl_prop, fig_name='{}'.format(FreeSpace_before_lens.eid), phase=True, domains='sf')
+
+#%%
+dfl_aperture = deepcopy(dfl_prop)
+
+# line = (Aperture, FreeSpace_after_aperture)
+
+lat = OpticsLine(line, start=Aperture, stop=Aperture)
+dfl_aperture = propagate(lat, dfl_aperture)                
+plot_dfl(dfl_aperture, fig_name='{}'.format(Aperture.eid), phase=True)
+
+lat = OpticsLine(line, start=FreeSpace_after_aperture, stop=FreeSpace_after_aperture)
+dfl_aperture = propagate(lat, dfl_aperture)                
+plot_dfl(dfl_aperture, domains='s', fig_name='{}'.format(FreeSpace_after_aperture.eid), phase=True)
+plot_dfl(dfl_aperture, domains='k', fig_name='{}'.format(FreeSpace_after_aperture.eid), phase=True)
+
+#%%
+dfl_lens = deepcopy(dfl_aperture)
+
+# line = (MirrorSurface, Lens)
+
+lat = OpticsLine(line, start=MirrorSurface, stop=Lens)
+dfl_lens = propagate(lat, dfl_lens)                
+plot_dfl(dfl_lens, fig_name='{}'.format(Lens.eid), phase=True)
+
+#%%
+# line = (FreeSpace_to_the_sample)
+
+dfl_sample = deepcopy(dfl_lens)
+lat = OpticsLine(line, start=FreeSpace_to_the_sample, stop=FreeSpace_to_the_sample)
+dfl_sample = propagate(lat, dfl_sample)
+                
+plot_dfl(dfl_sample, fig_name='{}'.format(FreeSpace_to_the_sample.eid), phase=True)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/optics/demo_ap_rect_apscan.py b/demos/optics/demo_ap_rect_apscan.py
new file mode 100755
index 00000000..b845df4d
--- /dev/null
+++ b/demos/optics/demo_ap_rect_apscan.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3.6
+
+# C. Lechner, 2021-10-01
+# demo for scan of energy vs. rectangular aperture
+
+import math
+import matplotlib.pyplot as plt
+from ocelot.optics.wave import *
+from ocelot import ocelog
+plt.ion()
+ocelog.setLevel(logging.DEBUG)
+
+# generate a beam
+lambda0=1e-9
+field_at_waist = generate_gaussian_dfl(xlamds=lambda0, shape=(101,101,100), dgrid=(2e-3,2e-3,50e-6))
+
+# run aperture scan
+en,cutoffs=dfl_ap_rect_apscan(field_at_waist)
+
+# compare with OCELOT function...
+dfl=field_at_waist
+stuff=deepcopy(dfl)
+dfl_ap_rect(stuff, ap_x=2*cutoffs[2], ap_y=2*cutoffs[2]) # function modifies field!
+print('Comparing relative energy reduction by cut (values should be in agreement):')
+print('       OCELOT function dfl_ap_rect: {}'.format(stuff.E()/dfl.E()))
+print('OCELOT function dfl_ap_rect_apscan: {}'.format(en[2]/dfl.E()))
+
+
+### plot the result
+fig,axs = plt.subplots(2,1)
+axs[0].plot(cutoffs,np.array(en)/dfl.E())
+axs[0].set_ylabel('rel. energy transmission E/E0')
+axs[1].semilogy(cutoffs,1-np.array(en)/dfl.E())
+axs[1].set_ylabel('rel. energy reduction, 1-E/E0')
+axs[1].set_xlabel('half-size of quadratic aperture [m]')
+axs[1].set_ylim([1e-6,1])
+plt.show()
diff --git a/demos/other/beam2edist2beam.py b/demos/other/beam2edist2beam.py
new file mode 100644
index 00000000..710f18ca
--- /dev/null
+++ b/demos/other/beam2edist2beam.py
@@ -0,0 +1,64 @@
+from ocelot.cpbd.beam import BeamArray, generate_beam
+from ocelot.adaptors.genesis import edist2beam, beam2edist
+from ocelot.gui.beam_plot import plot_beam
+from ocelot.gui.genesis_plot import plot_edist
+
+import numpy as np
+from ocelot.common.globals import *
+"""
+Created on Mon Jan  6 20:29:09 2020
+
+@author: andrei
+"""
+
+# Create electron beam file (slice parameters) with polynomial energy chirp, quadratic beta, emittance, energy spread and non-zero alpha. Plot it.
+beam = BeamArray()
+beam = generate_beam(E=20.0, dE=2.5e-3, I=5000, l_beam=1e-6, emit_n=0.5e-6, beta=20, l_window=6e-6, shape='gaussian')
+s0 = (np.max(beam.s) - np.min(beam.s))/ 2
+beta_x0 = 15
+beta_x0 = 15
+emit_x0 = beam.emit_x[1]
+emit_y0 = beam.emit_y[1]
+dg0 = 6
+beam.beta_x = beta_x0*(1 + 0.008*(beam.s - s0)**2/2 / (speed_of_light * 1e-15)**2 )
+beam.beta_y = beta_x0*(1-0.4 + 0.006*(beam.s - s0)**2/2 / (speed_of_light * 1e-15)**2 )
+beam.emit_x = emit_x0*(1+0.2 + 0.05*(beam.s - s0)**2/2 / (speed_of_light * 1e-15)**2 )
+beam.emit_y = emit_y0*(1 + 0.01*(beam.s - s0)**2/2 / (speed_of_light * 1e-15)**2 )
+
+beam.dg = dg0*(1 + 0.01*(beam.s - s0)**2/2 / (speed_of_light * 1e-15)**2 )
+
+beam.x = np.ones_like(beam.beta_x) * 1e-6
+beam.yp = np.ones_like(beam.beta_x) * 1e-6
+
+alpha_x = np.empty(np.shape(beam.s)[0])
+alpha_x.fill(1)
+alpha_y = np.empty(np.shape(beam.s)[0])
+alpha_y.fill(-1)
+beam.alpha_x = alpha_x
+beam.alpha_y = alpha_y
+beam.add_chirp_poly(coeff=[0.0, +5., -1, -0, 0.01], s0=None)
+plot_beam(beam, showfig=1, savefig=0, fig='Original beam')
+
+# Convert it to randomly distributed particle distribution and plot
+edist = beam2edist(beam, npart=200000)
+plot_edist(edist, fig_name='Generated distribution')
+
+# recalculate slice parameters and generate another beam file
+beam1 = edist2beam(edist)
+plot_beam(beam1, showfig=1, savefig=0, fig='Re-calculated beam')
+
+#%% Plot XXp and YYp distribution to check correlation introduced by non-zero alpha
+bins=(150, 150, 150, 150)
+cmin=0
+
+plt.figure('X_Xp')
+plt.hist2d(edist.x * 1e6, edist.xp * 1e6, [bins[0], bins[1]])
+plt.xlabel('x [$\mu$m]')
+plt.ylabel('xp [$\mu$rad]')
+plt.show()
+
+plt.figure('Y_Yp')
+plt.hist2d(edist.y * 1e6, edist.yp * 1e6, [bins[0], bins[1]])
+plt.xlabel('y [$\mu$m]')
+plt.ylabel('yp [$\mu$rad]')
+plt.show()
\ No newline at end of file
diff --git a/demos/other/genesis4_preprocessor_sase1_quasistst.py b/demos/other/genesis4_preprocessor_sase1_quasistst.py
new file mode 100644
index 00000000..f4d60613
--- /dev/null
+++ b/demos/other/genesis4_preprocessor_sase1_quasistst.py
@@ -0,0 +1,111 @@
+import os
+import functools
+
+import ocelot
+from ocelot.gui.beam_plot import *
+from ocelot.adaptors.genesis4 import *
+from ocelot.gui.genesis4_plot import *
+
+_logger = logging.getLogger(__name__)
+ocelog.setLevel(logging.INFO)
+
+sim_directory = r'/gpfs/exfel/data/scratch/svitozar/projects/ocelot_test/genesis4/Ocelot/preprocessor_local/'
+
+E_photon = 7000 #eV
+
+beam = generate_beam(E=14.0, dE=2.5e-3, I=5000, l_beam=1e-6, emit_n=0.5e-6, beta=20, l_window=6e-6, shape='gaussian')
+tws_beam = Twiss(beam.pk())
+# beam.add_chirp_poly(coeff=[0.0, +5., -1, -0, 0.01], s0=None)
+
+sase_lat_pkg = create_fel_beamline('sase1')
+prepare_el_optics(beam, sase_lat_pkg, E_photon=E_photon, beta_av=20)
+
+# tws_beam = Twiss(beam.pk())
+# tws_lat =  twiss(sase_lat_pkg[0], tws_beam, nPoints=1000)
+# plot_opt_func(sase_lat_pkg[0], tws_lat, legend=False)
+# plt.show()
+# plot_beam(beam, showfig=1, savefig=0, fig='Original beam')
+
+sase_lat, _, _ = sase_lat_pkg
+
+# Create input container object
+ginp = Genesis4Input()
+ginp.filename = 'sase1.in'
+ginp.make_sequence(['setup', 'time', 'lattice', 'field', 'beam#imported', 'sponrad', 'track', 'write']) # defines an order of the the namelists
+
+# Edit name lists
+ginp.sequence['setup'].rootname = 'sase1'
+ginp.sequence['setup'].lattice = 'sase1.lat'
+ginp.sequence['setup'].beamline = 'SASE1'
+# ginp.sequence['setup'].gamma0 = 11357.82 # inserted using ginp.populate_sequence_beam()
+ginp.sequence['setup'].lambda0 = eV2lambda(E_photon) # reference wavelength
+ginp.sequence['setup'].delz = 0.1 # integration period [m]
+ginp.sequence['setup'].seed = 123456789 # (ipseed in gen2)
+ginp.sequence['setup'].npart = 8192
+ginp.sequence['setup'].nbins = 4
+ginp.sequence['setup'].one4one = 0
+ginp.sequence['setup'].shotnoise = 1
+
+#ginp.sequence['lattice'].zmatch = 20 # optional, already matched with OCELOT
+
+ginp.sequence['time'].slen = 5e-7 # [m] length of time window
+ginp.sequence['time'].sample = 30 # sampling in wavelengths ("zsep" in gen2)
+ginp.sequence['time'].time = 1 #time-dependent
+
+ginp.sequence['field'].power = 10e3 #small value to see both seed and noise
+ginp.sequence['field'].dgrid = 1e-04
+ginp.sequence['field'].ngrid = 151 # ("ncar" in gen2)
+ginp.sequence['field'].waist_size = 30e-6
+
+# ginp.sequence['beam'].gamma = 27397.321010594387
+# ginp.sequence['beam'].delgam = 4.8923787518918544
+# ginp.sequence['beam'].current = 4997.704842822041
+# ginp.sequence['beam'].ex = 5e-07
+# ginp.sequence['beam'].ey = 5e-07
+# ginp.sequence['beam'].betax = 24.748339004051143
+# ginp.sequence['beam'].betay = 14.54507411359195
+# ginp.sequence['beam'].alphax = 1.3348109600614686
+# ginp.sequence['beam'].alphay = -0.800438812327674
+# ginp.sequence['beam'].xcenter = 0.0
+# ginp.sequence['beam'].ycenter = 0.0
+# ginp.sequence['beam'].pxcenter = 0.0
+# ginp.sequence['beam'].pycenter = 0.0
+# ginp.sequence['beam'].bunch = 0
+# ginp.sequence['beam'].bunchphase = 0
+# ginp.sequence['beam'].emod = 0
+# ginp.sequence['beam'].emodphase = 0
+ginp.populate_sequence_beam(beam, 'beam#imported') # fills in all values from the Beam object
+
+ginp.sequence['sponrad'].seed = 123123 # for quantum fluctuation
+ginp.sequence['sponrad'].doLoss = 1 # (isravg in gen2)
+ginp.sequence['sponrad'].doSpread = 1 # (isrsig in gen2)
+
+ginp.sequence['write'].field = ginp.sequence['setup'].rootname
+ginp.sequence['write'].beam = ginp.sequence['setup'].rootname
+
+ginp.sequence['track'].zstop = 75
+ginp.sequence['track'].output_step = 3 # populate out file every nth integration step (iphsty in gen2)
+ginp.sequence['track'].field_dump_step = 0
+ginp.sequence['track'].beam_dump_step = 0
+ginp.sequence['track'].sort_step = 0
+
+ginp.attachments.lat = {'SASE1': sase_lat}
+sase_sim = Genesis4Simulation(ginp,
+                              exp_dir=os.path.join(sim_directory, 'Example-SASE1'),
+                              return_out=1, # after the simulation reads and returns output file as Genesis4Output object
+                              cleanup_afterwards=0, # deletes simulation files after the simulation (makes sence when return_out=1)
+                              exec_script_path = __file__,
+                              zstop=50)
+
+# Genesis4 simulation is usually started simply using
+sase_gout = sase_sim.run()
+
+# But as it is not installed here, let's just write the files
+# sase_sim.clean_output()
+# sase_sim.write_all_files()
+
+# plot_gen4_out_z(sase_gout, z=np.inf, showfig=0, savefig=1)
+# plot_gen4_out_z(sase_gout, z=0, showfig=0, savefig=1)
+# plot_gen4_out_e(sase_gout, showfig=0, savefig=1)
+# plot_gen4_out_ph(sase_gout, showfig=0, savefig=1)
+plot_gen4_out_all(sase_gout.filePath.replace('out.h5','*'), showfig=0, savefig=1) #plots reasonable ammount of output from .out, .fld and .par
\ No newline at end of file
diff --git a/demos/other/genesis4_preprocessor_sase1_quasistst_edist.py b/demos/other/genesis4_preprocessor_sase1_quasistst_edist.py
new file mode 100644
index 00000000..dca4a656
--- /dev/null
+++ b/demos/other/genesis4_preprocessor_sase1_quasistst_edist.py
@@ -0,0 +1,114 @@
+import os
+import functools
+
+import ocelot
+from ocelot.gui.beam_plot import *
+from ocelot.adaptors.genesis4 import *
+from ocelot.gui.genesis4_plot import *
+
+_logger = logging.getLogger(__name__)
+ocelog.setLevel(logging.INFO)
+
+sim_directory = r'/gpfs/exfel/data/scratch/svitozar/projects/ocelot_test/genesis4/Ocelot/preprocessor_local/'
+
+E_photon = 7000 #eV
+
+beam = generate_beam(E=14.0, dE=2.5e-3, I=5000, l_beam=1e-6, emit_n=0.5e-6, beta=20, l_window=6e-6, shape='gaussian')
+tws_beam = Twiss(beam.pk())
+# beam.add_chirp_poly(coeff=[0.0, +5., -1, -0, 0.01], s0=None)
+
+sase_lat_pkg = create_fel_beamline('sase1')
+prepare_el_optics(beam, sase_lat_pkg, E_photon=E_photon, beta_av=20)
+
+# tws_beam = Twiss(beam.pk())
+# tws_lat =  twiss(sase_lat_pkg[0], tws_beam, nPoints=1000)
+# plot_opt_func(sase_lat_pkg[0], tws_lat, legend=False)
+# plt.show()
+# plot_beam(beam, showfig=1, savefig=0, fig='Original beam')
+
+sase_lat, _, _ = sase_lat_pkg
+
+# Create input container object
+ginp = Genesis4Input()
+ginp.filename = 'sase1.in'
+ginp.make_sequence(['setup', 'time', 'lattice', 'field', 'importdistribution', 'sponrad', 'track', 'write']) # defines an order of the the namelists
+
+# Edit name lists
+ginp.sequence['setup'].rootname = 'sase1'
+ginp.sequence['setup'].lattice = 'sase1.lat'
+ginp.sequence['setup'].beamline = 'SASE1'
+# ginp.sequence['setup'].gamma0 = 11357.82 # inserted using ginp.populate_sequence_beam()
+ginp.sequence['setup'].lambda0 = eV2lambda(E_photon) # reference wavelength
+ginp.sequence['setup'].delz = 0.1 # integration period [m]
+ginp.sequence['setup'].seed = 123456789 # (ipseed in gen2)
+ginp.sequence['setup'].npart = 8192
+ginp.sequence['setup'].nbins = 4
+ginp.sequence['setup'].one4one = 0
+ginp.sequence['setup'].shotnoise = 1
+
+#ginp.sequence['lattice'].zmatch = 20 # optional, already matched with OCELOT
+
+ginp.sequence['time'].slen = 5e-7 # [m] length of time window
+ginp.sequence['time'].sample = 30 # sampling in wavelengths ("zsep" in gen2)
+ginp.sequence['time'].time = 1 #time-dependent
+
+ginp.sequence['field'].power = 10e3 #small value to see both seed and noise
+ginp.sequence['field'].dgrid = 1e-04
+ginp.sequence['field'].ngrid = 151 # ("ncar" in gen2)
+ginp.sequence['field'].waist_size = 30e-6
+
+# ginp.sequence['beam'].gamma = 27397.321010594387
+# ginp.sequence['beam'].delgam = 4.8923787518918544
+# ginp.sequence['beam'].current = 4997.704842822041
+# ginp.sequence['beam'].ex = 5e-07
+# ginp.sequence['beam'].ey = 5e-07
+# ginp.sequence['beam'].betax = 24.748339004051143
+# ginp.sequence['beam'].betay = 14.54507411359195
+# ginp.sequence['beam'].alphax = 1.3348109600614686
+# ginp.sequence['beam'].alphay = -0.800438812327674
+# ginp.sequence['beam'].xcenter = 0.0
+# ginp.sequence['beam'].ycenter = 0.0
+# ginp.sequence['beam'].pxcenter = 0.0
+# ginp.sequence['beam'].pycenter = 0.0
+# ginp.sequence['beam'].bunch = 0
+# ginp.sequence['beam'].bunchphase = 0
+# ginp.sequence['beam'].emod = 0
+# ginp.sequence['beam'].emodphase = 0
+# ginp.populate_sequence_beam(beam, 'beam#imported') # fills in all values from the Beam object
+
+ginp.sequence['importdistribution'].file = 'edist.h5'
+
+
+ginp.sequence['sponrad'].seed = 123123 # for quantum fluctuation
+ginp.sequence['sponrad'].doLoss = 1 # (isravg in gen2)
+ginp.sequence['sponrad'].doSpread = 1 # (isrsig in gen2)
+
+ginp.sequence['write'].field = ginp.sequence['setup'].rootname
+ginp.sequence['write'].beam = ginp.sequence['setup'].rootname
+
+ginp.sequence['track'].zstop = 75
+ginp.sequence['track'].output_step = 3 # populate out file every nth integration step (iphsty in gen2)
+ginp.sequence['track'].field_dump_step = 0
+ginp.sequence['track'].beam_dump_step = 0
+ginp.sequence['track'].sort_step = 0
+
+ginp.attachments.lat = {'SASE1': sase_lat}
+sase_sim = Genesis4Simulation(ginp,
+                              exp_dir=os.path.join(sim_directory, 'Example-SASE1'),
+                              return_out=1, # after the simulation reads and returns output file as Genesis4Output object
+                              cleanup_afterwards=0, # deletes simulation files after the simulation (makes sence when return_out=1)
+                              exec_script_path = __file__,
+                              zstop=50)
+
+# Genesis4 simulation is usually started simply using
+sase_gout = sase_sim.run()
+
+# But as it is not installed here, let's just write the files
+# sase_sim.clean_output()
+# sase_sim.write_all_files()
+
+# plot_gen4_out_z(sase_gout, z=np.inf, showfig=0, savefig=1)
+# plot_gen4_out_z(sase_gout, z=0, showfig=0, savefig=1)
+# plot_gen4_out_e(sase_gout, showfig=0, savefig=1)
+# plot_gen4_out_ph(sase_gout, showfig=0, savefig=1)
+plot_gen4_out_all(sase_gout.filePath.replace('out.h5','*'), showfig=0, savefig=1) #plots reasonable ammount of output from .out, .fld and .par
\ No newline at end of file
diff --git a/demos/other/mprefix.py b/demos/other/mprefix.py
new file mode 100644
index 00000000..80974bb0
--- /dev/null
+++ b/demos/other/mprefix.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+"""
+Spyder Editor
+
+@author: sserkez
+"""
+
+import numpy as np
+import time
+from ocelot.common.math_op import mprefix
+
+value = 0.5366e6
+# value = [0.5366e6, 0.0999e-6]
+# value = np.array([1,30,0.4,99,801])
+
+value_out, prefix_out, order = mprefix(value, order_bias=0.05)
+
+if np.isscalar(value_out):
+    print('{value}m = {value_out:.3f} {prefix_out}m'.format(value=value, value_out=value_out, prefix_out=prefix_out))
+else:
+    print(value_out, prefix_out)
+
+
+#%%
+
+# for i in range(0,1000):
+#     value = 1.1**i
+#     print('{:5e}:'.format(value))
+#     order_bias=0.05
+#     value_scaled, prefix, order = mprefix(value, order_bias=order_bias)
+#     print('order_bias={:}: {:3.2f} {:} '.format(order_bias, value_scaled, prefix), end = '')
+
+#     order_bias=0.15
+#     value_scaled, prefix, order = mprefix(value, order_bias=order_bias)
+#     print('    order_bias={:}: {:3.2f} {:} '.format(order_bias, value_scaled, prefix), end = '')
+#     time.sleep(0.05)
+    
+#     order_bias=0.333
+#     value_scaled, prefix, order = mprefix(value, order_bias=order_bias)
+#     print('    order_bias={:}: {:3.2f} {:} '.format(order_bias, value_scaled, prefix))
+#     time.sleep(0.05)
+    
+
diff --git a/ocelot/adaptors/genesis.py b/ocelot/adaptors/genesis.py
index 2a112455..f76e9bc3 100644
--- a/ocelot/adaptors/genesis.py
+++ b/ocelot/adaptors/genesis.py
@@ -178,6 +178,7 @@
 __DISTFILE__\n\
 __MAGFILE__\n\
  filetype ='ORIGINAL'\n\
+__EXPERT__\n\
  $end\n"
 
 # outputfile ='run.__RUNID__.gout'\n\
@@ -395,6 +396,12 @@ def __init__(self):
         self.ffspec = 0  # amplitude/phase values for spectrum calculation: 0 - on-axis power/phase along the pulse, -1 - the same in far field, 1 - near field total power
         
         self.shotnoise = 1
+
+        # Free-format text block that is copied to the end of the infile.
+        # This might break your simulation, so it is for experts.
+        # One possible use-case is with patched versions of genesis that
+        # accept additional options.
+        self.infile_expert = None
         
         # paths to files to import
         self.beamfile = None
@@ -417,6 +424,9 @@ def __init__(self):
         self.run_dir = None # directory to run simulation in
         self.exp_dir = None # if run_dir==None, it is created based on exp_dir
         
+        # self.inpfile_fullpath = None # full path to input file (if not None - overrides standard folder structure)
+        # self.outfile_fullpath = None # full path to input file (if not None - overrides standard folder structure)
+        
         self.inp_txt = _inputTemplate
         
         self.int_vals = ('npart', 'nbins','ncar', 'zsep', 'nslice', 'ntail') #continue
@@ -473,6 +483,13 @@ def input(self):
         # else:
             # inp_txt = inp_txt.replace("__TRAMA__\n", "")
 
+        if self.infile_expert is not None:
+            _logger.warning(ind_str + 'using infile_expert mode: incorrect usage of this expert function might break the simulation')
+            inp_txt = inp_txt.replace("__EXPERT__", self.infile_expert)   # NOT replacing "\n" in template string: If the user is only using single-line expert string (i.e. specifying one custom option), they don't have to provide trailing \n
+        else:
+            inp_txt = inp_txt.replace("__EXPERT__\n", "")
+
+
         for p in self.__dict__.keys():
             if p in self.int_vals:
                 val = int(self.__dict__[p])
@@ -1116,6 +1133,12 @@ def run_genesis(inp, launcher, read_level=2, assembly_ver='pyt', dfl_slipage_inc
         inp_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + str(inp.suffix) + '.inp'
         out_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + str(inp.suffix) + '.gout'
         stage_string = '.s' + str(inp.stageid)
+    
+    # #overrules the filenames
+    # if inp.inpfile_fullpath is not None:
+        # inp_path = inp.inpfile_fullpath
+    # if inp.outfile_fullpath is not None:
+        # out_path = np.outfile_fullpath
 
     inp_file = filename_from_path(inp_path)
     out_file = filename_from_path(out_path)
@@ -1190,17 +1213,16 @@ def run_genesis(inp, launcher, read_level=2, assembly_ver='pyt', dfl_slipage_inc
     launcher.launch()
     _logger.info(ind_str + 'genesis simulation time %.2f seconds' % (time.time() - genesis_time))
     # RUNNING GENESIS ###
-
+    
+    assembly_time = time.time()
+    
     if assembly_ver is not None:
         # genesis output slices assembly
         _logger.info(ind_str + 'assembling slices')
         _logger.debug(2 * ind_str + 'assembly_ver = {}'.format(assembly_ver))
         
-        assembly_time = time.time()
-
-        
         if assembly_ver == 'sys':
-
+            
             _logger.info(2 * ind_str + 'assembling *.out file')
             start_time = time.time()
             os.system('cat ' + out_path + '.slice* >> ' + out_path)
@@ -1479,8 +1501,16 @@ def generate_input(undulator, beam, E_photon = None, itdp=True, *args, **kwargs)
     inp.emity = beam.emit_yn
     
     # idx_0 = inp.beam.I>0
-    rxbeam = np.nanmax(np.sqrt(inp.beam.beta_x * inp.beam.emit_x))
-    rybeam = np.nanmax(np.sqrt(inp.beam.beta_y * inp.beam.emit_y))
+    # if beam.len() !>1 the following will throw (cf line 1456 above):
+    try:
+        rxbeam = np.nanmax(np.sqrt(inp.beam.beta_x * inp.beam.emit_x))
+        rybeam = np.nanmax(np.sqrt(inp.beam.beta_y * inp.beam.emit_y))
+    except AttributeError:
+        rxbeam = np.nanmax(np.sqrt(beam.beta_x * beam.emit_xn))
+        rybeam = np.nanmax(np.sqrt(beam.beta_y * beam.emit_yn))
+    except:
+        raise
+      
     inp.dgrid = np.nanmax([rxbeam, rybeam]) * 8 #due to bug in Genesis2 that crashes when electrons leave the mesh
 
     inp.hn=1 # should be flexible in the future
@@ -1524,7 +1554,7 @@ def generate_input(undulator, beam, E_photon = None, itdp=True, *args, **kwargs)
     return inp
 
 
-def get_genesis_launcher(launcher_program=None, launcher_argument=''):
+def get_genesis_launcher(launcher_program=None, launcher_argument=' < tmp.cmd | tee log',launcher_mpiParameters='-x PATH -x PYTHONPATH'):
     '''
     Returns MpiLauncher() object for given program
     '''
@@ -1533,11 +1563,13 @@ def get_genesis_launcher(launcher_program=None, launcher_argument=''):
     launcher = MpiLauncher()
     if launcher_program != None:
         launcher.program = launcher_program
+        launcher.argument = launcher_argument
+        launcher.mpiParameters = launcher_mpiParameters
     else:
         if host.startswith('max'):
-            launcher.program = '/data/netapp/xfel/products/genesis/genesis'
+            launcher.program = 'genesis'
             launcher.argument = ' < tmp.cmd | tee log'
-        launcher.mpiParameters = '-x PATH -x MPI_PYTHON_SITEARCH -x PYTHONPATH'  # added -n
+        launcher.mpiParameters = launcher_mpiParameters # added -n
     #launcher.nproc = nproc
     return launcher
 
@@ -1900,19 +1932,22 @@ def read_out_file_stat(proj_dir, stage, run_inp=[], param_inp=[], debug=1):
     _logger.debug(ind_str + 'done in %.2f seconds' % (time.time() - start_time))
     return out_stat
 
-def read_out_file_stat_u(file_tamplate, run_inp=[], param_inp=[], debug=1):
+def read_out_file_stat_u(file_template, run_inp=[], param_inp=[], debug=1):
     '''
     reads statistical info of Genesis simulations,
     universal function for non-standard exp. folder structure
     returns GenStatOutput() object
 
-    file_tamplate = template of the .out file path with # denoting run number
+    file_template = template of the .out file path with # denoting run number or * (wildcart) denoting part of string to be arbitrary.
     run_inp - list of genesis runs to be looked for [0:1000] by default
     param_inp - list of genesis output parameters to be processed
     debug - see read_out_file()
     '''
+    
+    import glob
+    
     _logger.info('reading stat genesis output')
-    _logger.info(ind_str + 'file_tamplate = {}'.format(file_tamplate))
+    _logger.info(ind_str + 'file_template = {}'.format(file_template))
     _logger.debug(ind_str + 'run_inp = {}'.format(str(run_inp)))
     _logger.debug(ind_str + 'param_inp = {}'.format(str(param_inp)))
     start_time = time.time()
@@ -1929,17 +1964,36 @@ def read_out_file_stat_u(file_tamplate, run_inp=[], param_inp=[], debug=1):
         run_range = run_inp
 
     run_range_good = []
-
-    for irun in run_range:
-        out_file = file_tamplate.replace('#',str(irun))
-        if os.path.isfile(out_file):
-            if debug > 0:
-                print ('      reading run', irun)
-            outlist[irun] = read_out_file(out_file, read_level=2, debug=1)
-            outlist[irun].calc_spec(npad=1)
-            # print(outlist[irun].freq_lamd[0])
-            run_range_good.append(irun)
-            # except:
+    
+    if '*' in file_template:
+        # outlist = []
+        for irun, file in enumerate(glob.glob(file_template)):
+            _logger.info(ind_str + 'reading file {}'.format(file))
+            _logger.info(2*ind_str + 'irun = {}'.format(irun))
+            # out = read_out_file(out_file, read_level=2)
+            # out.calc_spec(npad=1)
+            # outlist.append(out)
+            try:
+                outlist[irun] = read_out_file(file, read_level=2, debug=1)
+                outlist[irun].calc_spec(npad=1)
+                run_range_good.append(irun)
+            except:
+                pass
+            
+            if len(run_range_good) > 50:
+                break
+    else:
+            
+        for irun in run_range:
+            out_file = file_template.replace('#',str(irun))
+            if os.path.isfile(out_file):
+                if debug > 0:
+                    print ('      reading run', irun)
+                outlist[irun] = read_out_file(out_file, read_level=2, debug=1)
+                outlist[irun].calc_spec(npad=1)
+                # print(outlist[irun].freq_lamd[0])
+                run_range_good.append(irun)
+                # except:
     run_range = run_range_good
     
     # check if all gout have the same number of slices nSlice and history records nZ
@@ -1976,7 +2030,7 @@ def read_out_file_stat_u(file_tamplate, run_inp=[], param_inp=[], debug=1):
         setattr(out_stat, param, param_matrix)
 
     out_stat.stage = None
-    out_stat.dir = os.path.dirname(file_tamplate)
+    out_stat.dir = os.path.dirname(file_template)
     out_stat.run = run_range
     out_stat.z = outlist[irun].z #check if all the same!
     out_stat.s = outlist[irun].s
@@ -1995,7 +2049,7 @@ def read_out_file_stat_u(file_tamplate, run_inp=[], param_inp=[], debug=1):
 '''
 
 
-def read_dfl_file_out(out, filePath=None, debug=1):
+def read_dfl_file_out(out, filePath=None, harmonic=1, *args, **kwargs):
     '''
     More compact function than read_dfl_file() to read the file generated with known .out file
     Returns RadiationField object
@@ -2008,19 +2062,22 @@ def read_dfl_file_out(out, filePath=None, debug=1):
     _logger.debug(ind_str + 'opening handle ' + str(out))
     
     if os.path.isfile(str(out)):
-        out = read_out_file(out, read_level=0, debug=0)
+        out = read_out_file(out, read_level=0)
     if not isinstance(out, GenesisOutput):
         _logger.error('out is neither GenesisOutput() nor a valid path')
         raise ValueError('out is neither GenesisOutput() nor a valid path')
 
     if filePath is None:
         _logger.debug(ind_str + 'from out.filePath')
-        filePath = out.filePath + '.dfl'
+        if harmonic is not 1:
+            filePath = out.filePath + '.dfl' + str(harmonic)
+        else:
+            filePath = out.filePath + '.dfl'
     else:
         _logger.debug(ind_str + 'from filepath')
     _logger.debug(2*ind_str + filePath)
     
-    dfl = read_dfl_file(filePath, Nxy=out.ncar, Lxy=out.leng, zsep=out('zsep'), xlamds=out('xlamds'), debug=debug)
+    dfl = read_dfl_file(filePath, Nxy=out.ncar, Lxy=out.leng, zsep=out('zsep')*harmonic, xlamds=out('xlamds')/harmonic)
     return dfl
 
 
@@ -2246,7 +2303,7 @@ def dpa2edist(out, dpa, num_part=1e5, smear=1, debug=1):
     reads GenesisParticlesDump() object
     returns GenesisElectronDist() object
     num_part - desired approximate number of particles in edist
-    smear - whether to shuffle macroparticles smearing microbunching
+    smear - whether to shuffle macroparticles smearing microbunching and populating delz-1 slices
     '''
     import random
     start_time = time.time()
@@ -2325,6 +2382,7 @@ def dpa2edist(out, dpa, num_part=1e5, smear=1, debug=1):
     edist.g = np.flipud(edist.g)
 
     edist.part_charge = out.beam_charge / edist.len()
+    _logger.debug(ind_str + 'edist.part_charge / q_e = ' + str(edist.part_charge / q_e))
     _logger.debug(ind_str + 'edist.len() = ' + str(edist.len()))
     # edist.charge=out.beam_charge
     if hasattr(dpa, 'filePath'):
@@ -2555,9 +2613,9 @@ def disperse_edist(edist, R56, debug=1):
     Introduces dispersion (good for simulating weak chicanes)
     delays or advances time coordinate of the particles depending on ther energy with respect to the averaged energy
     '''
-    _logger.info('introducing dispersion to particle distribution file with R56 '+ str(R56) + ' m')
+    _logger.info('introducing dispersion to particle distribution file with R56 {:.3e} m'.format(R56))
     if not isinstance(edist, GenesisElectronDist):
-        raise ValueError('out is neither GenesisOutput() nor a valid path')
+        raise ValueError('out is neither GenesisOutput() object nor a valid path')
     
     edist_out = deepcopy(edist)
     edist_out.t += R56 * (edist_out.g - np.mean(edist_out.g)) / edist_out.g / speed_of_light
@@ -2639,7 +2697,7 @@ def write_edist_file(edist, filePath=None, debug=1):
     _logger.debug(ind_str + 'done in %.2f sec' % (time.time() - start_time))
 
 
-def edist2beam(edist, step=2e-7): #check
+def edist2beam(edist, step=2e-7): #TODO: move to cpbd
     '''
     reads GenesisElectronDist()
     returns BeamArray()
@@ -2668,7 +2726,10 @@ def edist2beam(edist, step=2e-7): #check
             dist_y = edist.y[indices]
             dist_xp = edist.xp[indices]
             dist_yp = edist.yp[indices]
-            dist_sigma_E = np.std(dist_g) * m_e_GeV
+            
+            a, b = np.polyfit(edist.t[indices], dist_g, deg=1) #correction here!
+            dist_sigma_E = np.std(dist_g - a*edist.t[indices]) * m_e_GeV #correction here!
+            # dist_sigma_E = np.std(dist_g) * m_e_GeV
             dist_p = np.sqrt(dist_g**2 - 1)
             dist_px = dist_xp * dist_p
             dist_py = dist_yp * dist_p
@@ -2716,6 +2777,82 @@ def edist2beam(edist, step=2e-7): #check
     BEAM
 '''
 
+def beam2edist(beam, npart=10000): #TODO: move to cpbd
+    """
+    Creates electron beam particle distribution with random (not shot-noise-accounted-for) particle distribution
+    baased on Twiss parameters from beam
+    
+    reads BeamArray()
+    returns GenesisElectronDist()
+    beam: BeamArray() object
+    npart: number of particles
+    
+    """
+    # dist='gaussian'
+    # npart = 100000
+    
+    P = beam.I/np.sum(beam.I)
+    pack = np.round(P*npart)
+    
+    edist = GenesisElectronDist()
+    
+    t = np.empty(beam.len()-1, dtype=object)
+    g = np.empty(beam.len()-1, dtype=object)
+    dist_x = np.empty(beam.len()-1, dtype=object)
+    dist_xp = np.empty(beam.len()-1, dtype=object)
+    dist_y = np.empty(beam.len()-1, dtype=object)
+    dist_yp = np.empty(beam.len()-1, dtype=object)
+    
+    for i in range(beam.len()-1): 
+         
+        t1 = beam.s[i]/speed_of_light 
+        t2 = beam.s[i + 1]/speed_of_light 
+        
+        t[i] = np.random.uniform(t1, t2, size=int(pack[i])) #TODO:replace by linear splines
+    
+        g1 = beam.E[i]/m_e_GeV
+        g2 = beam.E[i+1]/m_e_GeV
+        
+        #use the inverse function method for generating g distribution on a small segment
+        g[i] = (t[i]-t1)*(g2 - g1)/(t2- t1) + np.random.normal(loc=g1, scale=beam.dg[i], size=int(pack[i])) 
+    
+        x = beam.x[i]
+        xp = beam.xp[i]
+        
+        y = beam.y[i]
+        yp = beam.yp[i]
+        
+        emit_x = beam.emit_x[i]
+        emit_y = beam.emit_y[i]
+        
+        beta_x = beam.beta_x[i]
+        beta_y = beam.beta_y[i]
+        
+        alpha_x = beam.alpha_x[i]
+        alpha_y = beam.alpha_y[i]
+        
+        gamma_x = (1 + alpha_x**2)/beta_x 
+        gamma_y = (1 + alpha_y**2)/beta_y
+        
+        # if dist in ['gaussian', 'g']:
+        mean_x_xp = [x, xp]
+        cov_x_xp = [[emit_x*beta_x, -alpha_x*emit_x],[-alpha_x*emit_x, emit_x*gamma_x]]
+        dist_x[i], dist_xp[i] = np.random.multivariate_normal(mean_x_xp, cov_x_xp, int(pack[i])).T
+        
+        mean_y_yp = [y, yp]
+        cov_y_yp = [[emit_y*beta_y, -alpha_y*emit_y],[-alpha_y*emit_y, emit_y*gamma_y]]
+        dist_y[i], dist_yp[i] = np.random.multivariate_normal(mean_y_yp, cov_y_yp, int(pack[i])).T
+    
+    edist.t = np.concatenate(t)
+    edist.g = np.concatenate(g)
+    edist.x = np.concatenate(dist_x)
+    edist.xp = np.concatenate(dist_xp)
+    edist.y = np.concatenate(dist_y)
+    edist.yp = np.concatenate(dist_yp)     
+       
+    edist.part_charge = beam.charge()/edist.len()
+    return edist
+
 
 # def read_beam_file_out(out, debug=1):
     # return read_beam_file(out.filePath, debug=debug)
diff --git a/ocelot/adaptors/genesis4.py b/ocelot/adaptors/genesis4.py
index c2dc370b..8c5553ad 100644
--- a/ocelot/adaptors/genesis4.py
+++ b/ocelot/adaptors/genesis4.py
@@ -1,137 +1,718 @@
 import time
 import os
+import sys
 import socket
 import copy
 
 try:
     import h5py
+
     h5py_avail = True
 except ImportError:
     print("wave.py: module h5py is not installed. Install it if you want to use genesis4 adaptor")
     h5py_avail = False
 
 import numpy as np
+
 from ocelot import ParticleArray
 from ocelot.optics.wave import calc_ph_sp_dens, RadiationField
 from ocelot.common.globals import *
-from ocelot.adaptors.genesis import GenesisElectronDist #tmp
+from ocelot.adaptors.genesis import GenesisElectronDist  # tmp
 from ocelot.common.ocelog import *
 from ocelot.utils.launcher import *
-import os
+from ocelot.cpbd.beam import Beam, BeamArray
+from ocelot.cpbd.elements import Element, Drift, Quadrupole, Undulator, Marker
+from ocelot.cpbd.magnetic_lattice import MagneticLattice
+from ocelot.common.py_func import copy_this_script
 
 _logger = logging.getLogger(__name__)
 
-_inputGen4Template = "\
- $newrun \n\
- aw0   =  __AW0__ \n\
- xkx   =  __XKX__\n\
- \n"
+# TODO: move to cpbd (enentually?)
+class Chicane(Element):
+    """
+    chicane (implemented for Genesis4, not used by cpbd)
+    l - length of chicane in [m],
+    lb - length of an individual dipole [m],
+    ld - drift between the outer and inner dipoles [m],
+    delay - path length difference between the straight path and the actual trajectory [rad].
+    """
+
+    def __init__(self, l=0., lb=0., ld=0., delay=0., eid=None):
+        # Element.__init__(self, eid)
+        super(Chicane, self).__init__(eid=eid)
+        self.l = l
+        self.lb = lb
+        self.ld = ld
+        self.delay = delay
 
 
-class Namespace:
-        def __init__(self):
+class Phaseshifter(Element):
+    """
+    phase shifter element (implemented for Genesis4, not used by cpbd)
+    l - length of phase shifter in [m]
+    phi = introduced phase shift in [rad] 
+    """
+
+    def __init__(self, l=0., phi=0., eid=None):
+        # Element.__init__(self, eid)
+        super(Phaseshifter, self).__init__(eid=eid)
+        self.l = l
+        self.phi = phi
+
+
+                           
+                                                      
+                                                                                                 
+                                          
+              
+
+
+class Genesis4Simulation:
+    """
+    Class for storing Genesis4 simulation parameters such as
+    input file,
+    settings for returning, plotting or cleaning output
+    """
+
+    def __init__(self, ginp=None, exp_dir='', **kwargs):
+
+        self.mpiParameters = ''
+        if ginp is not None:
+            self.ginp = ginp
+        else:
+            self.ginp = Genesis4Input()
+
+        self.exp_dir = exp_dir  # directory in which simulation will take place, i.e. input and output files will be written
+
+        # self.del_files = ('gout', 'fld', 'par')
+
+        self.plot_output = kwargs.get('plot_output', True)
+        self.return_out = kwargs.get('return_out', True)
+        self.cleanup_afterwards = kwargs.get('cleanup_afterwards', False)
+        self.zstop = kwargs.get('zstop', np.inf)
+        self.exec_script_path = kwargs.get('exec_script_path', None)
+        self.launcher = kwargs.get('launcher', get_genesis4_launcher())
+
+    @property
+    def root_name(self):
+        return self.ginp.setup.rootname
+
+    @root_name.setter
+    def root_name(self, value):
+        self.ginp.setup.rootname = value
+
+    def filepath(self, filename):
+        return os.path.join(self.exp_dir, filename)
+
+    def input_filepath(self):
+        return self.filepath(self.ginp.filename)
+
+    def root_path(self):
+        return self.filepath(self.root_name)
+
+    def create_exp_dir(self):
+        if not os.path.isdir(self.exp_dir):
+            os.makedirs(self.exp_dir)
+
+    def write_inp_file(self):
+        with open(self.input_filepath(), 'w') as file:
+            inp_string = str(self.ginp)
+            file.write(inp_string)
+
+    def write_lat_file(self):
+        write_gen4_lat(self.ginp.attachments.lat, filepath=self.filepath(self.ginp.setup.lattice),
+                       zstop=self.zstop)
+
+    def write_dfl_files(self):
+        """
+        Writes down dfl files for &importfield Genesis1.3-version4 name lists
+        :return:
+        """
+        for element_id in self.ginp.sequence.keys():
+            if element_id.startswith('importfield'):
+                impfld = self.ginp.sequence[element_id]
+                if impfld._name_list_id in self.ginp.attachments.dfl.keys():
+                    if impfld.file is not None:
+                        filename = self.filepath(impfld.file)
+                    else:
+                        filename = self.filepath(impfld._name_list_id + 'dfl.h5')
+                        impfld.file = filename
+                    write_dfl4(self.ginp.attachments.dfl[impfld._name_list_id], filename)
+
+        # for name_list_id, dfl in self.ginp.attachments.dfl: #TODO: iterate over namespaces, not attachments. If there is importing namespace without attachments 
+        # if not isinstance(dfl, str):
+        # write_dfl4(dfl, self.ginp.sequence[name_list_id].file)
+
+    def write_dpa_files(self):
+        """
+        NOT IMPLEMENTED YET
+        Writes down dpa files for &importbeam Genesis1.3-version4 name lists
+        :return:
+        """
+        for element in self.ginp.sequence:
+            if element.startswith('importbeam'):
+                imppar = self.ginp.sequence[element]
+                if imppar._name_list_id in self.ginp.attachments.dpa:
+                    if imppar.file is not None:
+                        filename = imppar.file
+                    else:
+                        filename = imppar._name_list_id + 'par.h5'
+                        imppar.file = filename
+                    # write_dpa4(self.attachments.dpa[imppar._name_list_id], filename)
+
+    def write_beam_files(self):
+        for element_id in self.ginp.sequence.keys():
+            if element_id.startswith('beam'):
+                impbeam = self.ginp.sequence[element_id]
+                if impbeam._name_list_id in self.ginp.attachments.beam.keys():
+                    file_path = self.filepath(impbeam._name_list_id + '.beam.h5')
+                    write_beamtwiss_hdf5(self.ginp.attachments.beam[impbeam._name_list_id], file_path)
+
+    def write_all_files(self):
+        self.create_exp_dir()
+        self.write_inp_file()
+                             
+        self.write_dfl_files()
+        self.write_beam_files()
+        self.write_lat_file()
+        
+        if self.exec_script_path is not None:
+            copy_this_script(self.exec_script_path, self.exp_dir)
+        # TODO: write all attachments
+
+    def prepare_launcher(self, program_path='genesis4'):
+        self.launcher.program = program_path
+        self.launcher.dir = self.exp_dir
+        self.launcher.argument = ' ' + self.ginp.filename
+        self.mpiParameters = '-np 8'  # TODO: calculate and request minimum reasonable number of cores (to not ovewblow the window) S.S.
+
+        # TODO: implement on Launcher level
+        if sys.platform not in ["linux", "linux2"]:
+            _logger.error('Only linux platform supported for given launcher (at the moment)')
             pass
 
+    def run(self, launcher=None):
+        self.prepare_launcher()
+        if launcher is not None:
+            self.launcher = launcher
+        self.clean_output()
+        self.write_all_files()
+
+        self.launcher.launch()
+
+        if self.return_out:
+            out = read_gout4(self.root_path() + '.out.h5')
+        else:
+            out = None
+
+        if self.cleanup_afterwards:
+            self.clean_output()
+
+        return out
+
+    def clean_output(self):
+        os.system('rm -r {}*'.format(self.root_path()))
 
 
 class Genesis4Input:
-    '''
-    Genesis input files storage object
-    '''
+    """
+    Ocelot container class to store Genesis4 input parameters
+    """
+
+    def __init__(self):
+        self.sequence = {}  # sequence of namespaces; each value starts with a supported namespace name, e.g. "field" and if needed is followed by unique suffix after pound symbol, like "field#2"
+        self.attachments = Genesis4Attachments()
+        # self.add_prefix_attributes = ['setup.lattice', 'setup.rootname', 'filename', 'write.field', 'write.beam']
+        self.filename = 'input.in'
+
+    def __str__(self):
+        str_out = '# autogenerated with Ocelot\n\n'  # https://github.com/ocelot-collab/ocelot\n\n
+        for name_list in self.sequence.values():
+            str_out += '&' + name_list._name_list_label + '\n'
+            str_out += str(name_list)
+            str_out += '&end\n\n'
+        return str_out
+
+    def make_sequence(self, gen4_name_lists_ids=None):
+        """
+        returns simple sequence based on default genesis 4 namespace order.
+        will not work with advanced beamlines
+        """
+        self.sequence = {}
+
+        name_list_subclasses = {}
+        for name_list_subclass in Genesis4NameList.__subclasses__():
+            name_list_subclasses[name_list_subclass()._name_list_label] = name_list_subclass
+
+        for name_list_id in gen4_name_lists_ids:
+            if '#' in name_list_id:
+                temp, _ = name_list_id.split('#')
+            else:
+                temp = name_list_id
+            self.sequence[name_list_id] = name_list_subclasses[temp](name_list_id)
+        self.check_consistency()
+
+    # def make_sequence_simple(self):
+    #     attrs = ['setup', 'lattice', 'time', 'importdistribution', 'importbeam', 'beam', 'importfield', 'field',
+    #              'track', 'write']
+    #     self.make_sequence(attrs)
+
+    @property
+    def setup(self):
+        for name_list in self.sequence.values():
+            if isinstance(name_list, Genesis4SetupNL):
+                return name_list
+
+    def check_consistency(self):
+        """
+        checks if beam of field are not declared few times before tracking
+        """
+        beam_counter = 0
+        field_counter = 0
+        for id, name_list in self.sequence.items():
+            if isinstance(name_list, (Genesis4BeamNL, Genesis4ImportBeamNL, Genesis4ImportDistributionNL)):
+                beam_counter += 1
+            if isinstance(name_list, (Genesis4FieldNL, Genesis4ImportFieldNL)):
+                field_counter += 1
+            if isinstance(name_list, (Genesis4TrackNL,)):
+                if beam_counter != 1:
+                    _logger.error(
+                        'Genesis4Input.sequence contains more or less than one declaration of beam')  # TODO: specify, 0 or >1
+                if field_counter != 1:
+                    _logger.error('Genesis4Input.sequence contains more or less than one declaration of field')
+                field_counter = 0
+                beam_counter = 0
+        # TODO: decide whether error raising is needed if co-exist e.g. importbeam and beam or importfield and field
+
+    def populate_sequence_beam_array(self, beam_name_list_id, beam=None):
+        _logger.info('Populating beam_array to Genesis4Input.sequence')
+        if beam_name_list_id not in self.attachments.beam.keys():
+            if beam is None:
+                _logger.warning(ind_str + 'no beam_array to populate')
+            else:
+                self.attachments.beam[beam_name_list_id] = beam
+                self.sequence['setup'].gamma0 = np.mean(beam.g)
+                self.sequence['time'].slen = np.amax(beam.s) - np.amin(beam.s)
+        new_sequence = {}
+        for name_list_id, name_list in self.sequence.items():
+            if name_list_id != beam_name_list_id:
+                new_sequence[name_list_id] = name_list
+            else:
+                for attr in self.sequence[beam_name_list_id].__dict__.keys():
+                    if attr.startswith('_'):
+                        continue
+                    profile_name_list_id = 'profile_file#' + attr + '_' + beam_name_list_id
+                    new_sequence[profile_name_list_id] = Genesis4ProfileFileNL()
+                    new_sequence[profile_name_list_id].label = attr + '_' + beam_name_list_id.replace('#', '')
+                    new_sequence[profile_name_list_id].xdata = beam_name_list_id + '.beam.h5/s'
+                    new_sequence[profile_name_list_id].ydata = beam_name_list_id + '.beam.h5/' + attr
+                new_sequence[name_list_id] = name_list
+                for attr in self.sequence[beam_name_list_id].__dict__.keys():
+                    if attr.startswith('_'):
+                        continue
+                    profile_file_label = '@' + attr + '_' + beam_name_list_id.replace('#', '')
+                    setattr(new_sequence[name_list_id], attr, profile_file_label)
+        self.sequence = new_sequence
+
+
+    def populate_sequence_beam(self, beam, name_list_id):
+        """
+        :param self: Genesis4Input
+        :param beam: BeamArray or Beam object
+        :param name_list_id:
+        :return: None
+        """
+        if isinstance(beam, BeamArray):
+            beam_pk = beam.pk()
+            _logger.warning(
+                'at the moment method beam_to_sequence_beam parses a single beam slice; peak current value is taken')
+        elif isinstance(beam, Beam):
+            beam_pk = beam
+        else:
+            raise TypeError('beam should be an instance of BeamArray or Beam')
+        self.sequence['setup'].gamma0 = beam_pk.g
+        self.sequence['time'].slen = np.amax(beam.s) - np.amin(beam.s)
+        self.sequence[name_list_id].gamma = beam_pk.g  # from [GeV] to [units of the electron rest mass]
+        self.sequence[name_list_id].delgam = beam_pk.dg
+        self.sequence[name_list_id].current = beam_pk.I
+        self.sequence[name_list_id].ex = beam_pk.emit_xn
+        self.sequence[name_list_id].ey = beam_pk.emit_yn
+        self.sequence[name_list_id].betax = beam_pk.beta_x
+        self.sequence[name_list_id].betay = beam_pk.beta_y
+        self.sequence[name_list_id].alphax = beam_pk.alpha_x
+        self.sequence[name_list_id].alphay = beam_pk.alpha_y
+        self.sequence[name_list_id].xcenter = beam_pk.x
+        self.sequence[name_list_id].ycenter = beam_pk.y
+        self.sequence[name_list_id].pxcenter = beam_pk.px
+        self.sequence[name_list_id].pycenter = beam_pk.py
+        self.sequence[name_list_id].bunch = 0
+        self.sequence[name_list_id].bunchphase = 0
+        self.sequence[name_list_id].emod = 0
+        self.sequence[name_list_id].emodphase = 0
+
+    # def add_prefixes(self, prefix_str):
+    #     def rsetattr(obj, attr, val):
+    #         pre, _, post = attr.rpartition('.')
+    #         return setattr(rgetattr(obj, pre) if pre else obj, post, val)
+    #
+    #     def rgetattr(obj, attr, *args):
+    #         def _getattr(obj, attr):
+    #             return getattr(obj, attr, *args)
+    #
+    #         return functools.reduce(_getattr, [obj] + attr.split('.'))
+    #
+    #     for attr in self.add_prefix_attributes:
+    #         try:
+    #             oldvalue = rgetattr(self, attr)
+    #             if oldvalue not in [None, '']:
+    #                 # print(rgetattr(self, attr))
+    #                 rsetattr(self, attr, prefix_str + oldvalue)
+    #                 # print(rgetattr(self, attr))
+    #         except:
+    #             # _logger.debug...
+    #             pass
+
+
+class Genesis4Attachments:
+    # TODO: think about possibility to attach and write several dfls, lattices, etc.
     def __init__(self):
+        self.dfl = {}  # e.g. {key1: fld1, key2: fld2} where key is "_name_list_id" of Genesis4ImportFieldNL file should be written as <Genesis4ImportFieldNL.file>.fld
+        self.dpa = {}  # e.g. {key1: par1, key2: par2} where key is "_name_list_id" of Genesis4ImportBeamNL file should be written as <Genesis4ImportBeamNL.file>.par
+        self.beam = {}
+        self.lat = {}  # e.g. {key1: lat1, key2: lat2}, where key is the value of setup.lattice
+
+
+# def genesis4_input(input_sequence=tuple()):
+#    str_out = ''
+#    for name_list in input_sequence:
+#        str_out += '&' + name_list._name_list_label + '\n'
+#        str_out += str(name_list)
+#        str_out += '&end\n\n'
+#    return str_out
+
+# %%
+class Genesis4NameList(object):
+    """
+    Parent object for Genesis 4 namelists
+    str(Genesis4NameList) yields the list text
+    attributes not starting with underscore "_" are considered Genesis4NameList variables
+    """
+
+    # def attr_list(self):
+    #     output_list = dir(self)
+    #     for attr in dir(self):
+    #         if attr.startswith('_') or callable(getattr(self, attr)):
+    #             output_list.remove(attr)
+    #     return output_list
+
+    # def all_attrs_is_none(self):
+    #    for attr in self.attr_list():
+    #        if getattr(self, attr) is not None:
+    #            return False
+    #    return True
+
+    # def attr_list(self):
+    #     output_list = dir(self)
+    #     for attr in dir(self):
+    #         if attr.startswith('_') or callable(getattr(self, attr)):
+    #             output_list.remove(attr)
+    #     return output_list
+
+    def name_list_id_set(self, name_list_id=None):
+        self._name_list_id = name_list_id if name_list_id is not None else self._name_list_label
+
+    def __str__(self):
+        str_out = ''
+        for attr, value in self.__dict__.items():
+            if attr.startswith('_'):
+                continue
+            if value is True:
+                value = 'true'
+            elif value is False:
+                value = 'false'
+            if value is not None:
+                str_out += attr + ' = ' + str(value) + '\n'
+        return str_out
+
+
+class Genesis4SetupNL(Genesis4NameList):
+
+    def __init__(self,
+                 name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'setup'
+        self.name_list_id_set(name_list_id)
+        self.rootname = 'output'  # name of all files generated by simulation
+        self.lattice = None
+        self.beamline = None
+        self.gamma0 = None
+        self.lambda0 = None
+        self.delz = None
+        self.seed = None
+        self.npart = None
+        self.nbins = None
+        self.one4one = None
+        self.shotnoise = None
+
+
+class Genesis4AlterSetupNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'alter_setup'
+        self.name_list_id_set(name_list_id)
+        self.rootname = None
+        self.beamline = None
+        self.delz = None
+        self.harmonic = None
+        self.subharmonic = None
+        self.resample = None
+
+
+class Genesis4LatticeNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'lattice'
+        self.name_list_id_set(name_list_id)
+        self.zmatch = None
+        self.element = None
+        self.field = None
+        self.value = None
+        self.instance = None
+        self.add = None
+
+
+class Genesis4TimeNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'time'
+        self.name_list_id_set(name_list_id)
+        self.s0 = None
+        self.slen = None
+        self.sample = None
+        self.time = None
+
+
+class Genesis4ProfileConstNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'profile_const'
+        self.name_list_id_set(name_list_id)
+        self.label = None
+        self.c0 = None
+
+
+class Genesis4ProfileGaussNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'profile_gauss'
+        self.name_list_id_set(name_list_id)
+        self.label = None
+        self.c0 = None
+        self.s0 = None
+        self.sig = None
+
+
+class Genesis4ProfileStepNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'profile_step'
+        self.name_list_id_set(name_list_id)
+        self.label = None
+        self.c0 = None
+        self.s_start = None
+        self.s_end = None
+
+
+class Genesis4ProfilePolynomNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'profile_polynom'
+        self.name_list_id_set(name_list_id)
+        self.label = None
+        self.c0 = None
+        self.c1 = None
+        self.c2 = None
+        self.c3 = None
+        self.c4 = None
+
+
+class Genesis4ProfileFileNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'profile_file'
+        self.name_list_id_set(name_list_id)
+        self.label = None
+        self.xdata = None
+        self.ydata = None
+        self.isTime = None
+        self.reverse = None
+
+
+class Genesis4BeamNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'beam'
+        self.name_list_id_set(name_list_id)
+        self.gamma = None
+        self.delgam = None
+        self.current = None
+        self.ex = None
+        self.ey = None
+        self.betax = None
+        self.betay = None
+        self.alphax = None
+        self.alphay = None
+        self.xcenter = None
+        self.ycenter = None
+        self.pxcenter = None
+        self.pycenter = None
+        self.bunch = None
+        self.bunchphase = None
+        self.emod = None
+        self.emodphase = None
+
+
+class Genesis4FieldNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'field'
+        self.name_list_id_set(name_list_id)
+        # setattr(self, 'lambda', None)
+        self.lambda_ = None  # must be lambda, but it is taken by Python for lambda-expressions
+        self.power = None
+        self.phase = None
+        self.waist_pos = None
+        self.waist_size = None
+        self.xcenter = None
+        self.ycenter = None
+        self.xangle = None
+        self.yangle = None
+        self.dgrid = None
+        self.ngrid = None
+        self.harm = None
+        self.nx = None
+        self.ny = None
+        self.accumulate = None
+
+    def __str__(self):
+        return super(Genesis4FieldNL, self).__str__().replace('lambda_', 'lambda')
+
+
+class Genesis4ImportDistributionNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'importdistribution'
+        self.name_list_id_set(name_list_id)
+        self.file = None
+        self.sdds = None
+        self.charge = None
+        self.slicewidth = None
+        self.output = None
+        self.center = None
+        self.gamma0 = None
+        self.x0 = None
+        self.y0 = None
+        self.px0 = None
+        self.py0 = None
+        self.match = None
+        self.betax = None
+        self.betay = None
+        self.alphax = None
+        self.alphay = None
+
+
+class Genesis4ImportFieldNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'importfield'
+        self.name_list_id_set(name_list_id)
+        self.file = None
+
+
+class Genesis4ImportBeamNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'importbeam'
+        self.name_list_id_set(name_list_id)
+        self.file = None
+
+
+class Genesis4EfieldNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'efield'
+        self.name_list_id_set(name_list_id)
+        self.rmax = None
+        self.nz = None
+        self.nphi = None
+        self.ngrid = None
+
+
+class Genesis4SponradNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'sponrad'
+        self.name_list_id_set(name_list_id)
+        self.seed = None
+        self.doLoss = None
+        self.doSpread = None
+
+
+class Genesis4SortNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'sort'
+        self.name_list_id_set(name_list_id)
+
+
+class Genesis4WakeNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'wake'
+        self.name_list_id_set(name_list_id)
+        self.loss = None
+        self.radius = None
+        self.roundpipe = None
+        self.conductivity = None
+        self.relaxation = None
+        self.material = None
+        self.gap = None
+        self.lgap = None
+        self.hrough = None
+        self.lrough = None
+        self.transient = None
+        self.ztrans = None
+
+
+class Genesis4WriteNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'write'
+        self.name_list_id_set(name_list_id)
+        self.field = None
+        self.beam = None
+
+
+class Genesis4TrackNL(Genesis4NameList):
+    def __init__(self, name_list_id=None):
+        # super().__init__()
+        self._name_list_label = 'track'
+        self.name_list_id_set(name_list_id)
+        self.zstop = None
+        self.output_step = None
+        self.field_dump_step = None
+        self.beam_dump_step = None
+        self.sort_step = None
 
-        self.setup = Namespace()
-        self.setup.rootname = ''
-        self.setup.lattice = ''
-        self.beamline = ''
-        self.gamma0 = 11350.3
-
-        self.alter_setup = Namespace()
-        self.lattice = Namespace()
-
-        self.exp_dir = None
-        self.run_dir = None
-
-        self.template = "\
-        rootname=try_genesis_s2_field     \n\
-        lattice=lattice.lat     \n\
-        beamline=SASE3     \n\
-        lambda0=1.77120e-9     \n\
-        gamma0=16634.08     \n\
-        delz=0.017     \n\
-        shotnoise=1     \n\
-        &end     \n\
-             \n\
-        &time     \n\
-        slen=2e-6     \n\
-        sample=12     \n\
-        &end     \n\
-             \n\
-        #&field     \n\
-        #power=0     \n\
-        #dgrid=3e-4     \n\
-        #ngrid=111     \n\
-        #waist_size=30e-6     \n\
-        #&end     \n\
-             \n\
-        &profile_gauss     \n\
-        label=prof2     \n\
-        c0=3000     \n\
-        s0=0.4e-6     \n\
-        sig=1e-6     \n\
-        &end     \n\
-             \n\
-        &profile_polynom     \n\
-        label=prof_lin     \n\
-        c0=0.3e-6     \n\
-        c1=0.01     \n\
-        &end     \n\
-             \n\
-        &beam     \n\
-        current=2000     \n\
-        delgam=3.5     \n\
-        ex=0.5e-6     \n\
-        ey=0.5e-6     \n\
-        alphax = 1.33377002518     \n\
-        alphay = -0.787227424221     \n\
-        betax = 25     \n\
-        betay = 15     \n\
-        &end     \n\
-             \n\
-        &importfield     \n\
-        file=try_genesis_s1.fld.h5     \n\
-        &end     \n\
-             \n\
-        #&importbeam     \n\
-        #file=try_genesis_s1.par.h5     \n\
-        #charge = 34e-12     \n\
-        #&end     \n\
-             \n\
-        #&lattice     \n\
-        #zmatch=5     \n\
-        #&end     \n\
-             \n\
-        &track     \n\
-        zstop=50     \n\
-        &end     \n\
-             \n\
-        &write     \n\
-        field=try_genesis_s2_field     \n\
-        beam=try_genesis_s2_field     \n\
-        &end     \n\
-        \n"
-
-    def input(self):
-        return self.template
 
 class Genesis4ParticlesDump:
-    '''
+    """
     Genesis particle *.dpa files storage object
     Each particle record in z starts with the energy of all particles 
     followed by the output of the particle phases, 
     positions in x and y and the momenta in x and y. 
     The momenta are normalized to mc
-    '''
+    """
 
     def __init__(self):
         self.g = []
@@ -152,12 +733,135 @@ def fileName(self):
         # return filename_from_path(self.filePath)
 
 
+def gen4_lat_str(lat, line_name='LINE', zstop=np.inf):
+    """
+    Generates a string of lattice 
+    in Genesis4 format
+    from an ocelot lattice object
+    """
+    from ocelot.cpbd.elements import Undulator, Drift, Quadrupole, UnknownElement
+    lat_str = []
+    beamline = []
+    location = 0
+
+    for element in lat.sequence:
+
+        if location >= zstop:
+            break
+
+        element_num = line_name + '_' + str(len(beamline) + 1).zfill(3)
+
+        if hasattr(element, 'l'):
+            location += element.l
+        else:
+            _logging.warning('[beta] element had no length: {:}'.format(str(element)))
+
+        if isinstance(element, Undulator):
+            element_name = element_num + 'UND'
+
+            if element.Kx == 0 or element.Ky == 0:
+                is_helical = 'false'
+            elif element.Kx == element.Ky:
+                is_helical = 'true'
+            else:
+                _logger.warning(
+                    'undulator element with different non-zero Kx and Ky; not implemented; setting to helical')
+                is_helical = 'true'
+            aw = np.sqrt((element.Kx ** 2 + element.Ky ** 2) / 2)
+            # TODO: implement ax,ay,kx,ky,gradx,grady
+            s = '{:}: UNDULATOR = {{lambdau = {:}, nwig = {:}, aw = {:.6f}, helical = {:}}};'.format(element_name,
+                                                                                                     element.lperiod,
+                                                                                                     element.nperiods,
+                                                                                                     aw, is_helical)
+
+        elif isinstance(element, Drift):
+            element_name = element_num + 'DR'
+            s = '{:}: DRIFT = {{l={:}}};'.format(element_name, element.l)
+
+        elif isinstance(element, Quadrupole):
+            # TODO: add dx and dy
+            if element.k1 >= 0:
+                element_name = element_num + 'QF'
+            else:
+                element_name = element_num + 'QD'
+            s = '{:}: QUADRUPOLE = {{l = {:}, k1 = {:.6f} }};'.format(element_name, element.l, element.k1)
+
+        elif isinstance(element, Chicane):
+            element_name = element_num + 'CH'
+            s = '{:}: CHICANE = {{l = {:}, lb = {:}, ld = {}, delay = {:.5e} }};'.format(element_name, element.l,
+                                                                                         element.lb, element.ld,
+                                                                                         element.delay)
+
+        elif isinstance(element, Marker):
+            element_name = element_num + 'M'
+            m_dumpfield = getattr(element, 'dumpfield', 0)
+            m_dumpbeam = getattr(element, 'dumpbeam', 0)
+            m_sort = getattr(element, 'sort', 0)
+            m_stop = getattr(element, 'stop', 0)
+            s = '{:}: MARKER = {{dumpfield = {:}, dumpbeam = {:}, sort = {:}, stop = {:} }};'.format(element_name,
+                                                                                                     m_dumpfield,
+                                                                                                     m_dumpbeam, m_sort,
+                                                                                                     m_stop)
+
+        elif isinstance(element, Phaseshifter):
+            element_name = element_num + 'PH'
+            s = '{:}: PHASESHIFTER = {{l = {:}, phi = {:}}};'.format(element_name, element.l, element.phi)
+
+        else:
+            _logger.warning('Unknown element {} with length {}\n replacing with drift'.format(str(element), element.l))
+            element_name = element_num + 'UNKNOWN'
+            s = '{:}: DRIFT = {{l={:}}};'.format(element_name, element.l)
+            continue
+
+        beamline.append(element_name)
+        lat_str.append(s)
+
+    lat_str.append('')
+    lat_str.append('{:}: LINE = {{{:}}};'.format(line_name, ','.join(beamline)))
+    lat_str = "\n".join(lat_str)
+    _logger.debug(ind_str + lat_str)
+    return lat_str
+
+
+def write_gen4_lat(lattices, filepath, zstop=np.inf):
+    """
+    Writing lattice file for Genesis1.3-version4 simulations
+    :param lattices: dictionary: {'line_name': ocelot.cpbd.magnetic_lattice.MagneticLattice(), ...}
+    :param filepath: str: path to the file in which lattices information will be writen
+    :param zstop: dict with active lengths for each lattice in lattices dictionary (can be a double if len(lattices)==1)
+    :return:
+    """
+    _logger.info('writing genesis4 lattice')
+    _logger.debug(ind_str + 'writing to ' + filepath)
+    _logger.debug('lattices = {}'.format(str(lattices)))
+    f = open(filepath, 'w')  # erasing file content
+    f.write('# generated with Ocelot\n')
+
+    if not isinstance(zstop, dict):
+        if type(lattices) != dict:
+            raise TypeError("type(lattices) != dict: lattices should be a dictionary with keys the same as lattices")
+        else:
+            lat_name = [key for key in lattices.keys()][0]
+            zstop = {lat_name: zstop}
+
+
+    for line_name, lat in zip(lattices.keys(), lattices.values()):
+        _logger.debug(ind_str + "line={}, lat={}, zstop={}".format(line_name, type(lat), zstop.get(line_name, np.inf)))
+        lat_str = gen4_lat_str(lat, line_name=line_name, zstop=zstop.get(line_name, np.inf))
+        f.write(lat_str)
+
+    f.write('\n# end of file')
+    f.close()
+    _logger.debug(ind_str + 'done')
+
+
 class Genesis4Output:
-    '''
+    """
     Genesis input files storage object
-    '''
+    """
+
     def __init__(self):
-        self.h5 = None #hdf5 pointer
+        self.h5 = None  # hdf5 pointer
 
     def close(self):
         self.h5.close()
@@ -223,10 +927,10 @@ def rad_field(self, zi=None, loc='near'):
             raise ValueError('loc should be either "far" or "near"')
 
         if zi is not None:
-            intens = intens[zi,:]
-            phase = phase[zi,:]
+            intens = intens[zi, :]
+            phase = phase[zi, :]
 
-        #not scaled properly!!!!
+        # not scaled properly!!!!
         field = np.sqrt(intens[:]) * np.exp(1j * phase[:])
         return field
 
@@ -235,25 +939,26 @@ def calc_spec(self, zi=None, loc='near', npad=1, estimate_ph_sp_dens=1):
         field = self.rad_field(zi=zi, loc=loc)
         axis = field.ndim - 1
 
-        spec = np.abs(np.fft.fft(field, axis=axis))**2
+        spec = np.abs(np.fft.fft(field, axis=axis)) ** 2
         spec = np.fft.fftshift(spec, axes=axis)
 
-        scale_ev = h_eV_s * speed_of_light * (np.fft.fftfreq(self.nSlices, d=self.s[1]-self.s[0]) + 1 / self.lambdaref)
+        scale_ev = h_eV_s * speed_of_light * (
+                np.fft.fftfreq(self.nSlices, d=self.s[1] - self.s[0]) + 1 / self.lambdaref)
         scale_ev = np.fft.fftshift(scale_ev)
 
         if estimate_ph_sp_dens:
-            tt=np.trapz(spec, scale_ev, axis=axis)
-            if axis==1:
-                tt[tt==0] = np.inf
+            tt = np.trapz(spec, scale_ev, axis=axis)
+            if axis == 1:
+                tt[tt == 0] = np.inf
                 spec *= (self.n_photons / tt)[:, np.newaxis]
             else:
-                if tt==0:
+                if tt == 0:
                     tt = np.inf
                 spec *= (self.n_photons[zi] / tt)
 
         return scale_ev, spec
 
-    def wig(self,z=np.inf):
+    def wig(self, z=np.inf):
         return wigner_out(self, z=z, method='mp', debug=1)
 
     def close(self):
@@ -262,9 +967,9 @@ def close(self):
 
 
 def get_genesis4_launcher(launcher_program='genesis4', launcher_argument=''):
-    '''
+    """
     Returns MpiLauncher() object for given program
-    '''
+    """
     host = socket.gethostname()
 
     launcher = MpiLauncher()
@@ -277,12 +982,13 @@ def get_genesis4_launcher(launcher_program='genesis4', launcher_argument=''):
     return launcher
 
 
+### USE FOR PILLAGE
 def run_genesis4(inp, launcher, *args, **kwargs):
-    '''
+    """
     Main function for executing Genesis code
     inp               - GenesisInput() object with genesis input parameters
     launcher          - MpiLauncher() object obtained via get_genesis_launcher() function
-    '''
+    """
     # import traceback
     _logger.info('Starting genesis v4 preparation')
     # _logger.warning(len(traceback.extract_stack()))
@@ -292,8 +998,8 @@ def run_genesis4(inp, launcher, *args, **kwargs):
         raise ValueError('run_dir and exp_dir are not specified!')
 
     if inp.run_dir is None:
-        if inp.exp_dir[-1]!=os.path.sep:
-            inp.exp_dir+=os.path.sep
+        if inp.exp_dir[-1] != os.path.sep:
+            inp.exp_dir += os.path.sep
         inp.run_dir = inp.exp_dir + 'run_' + str(inp.runid) + '/'
 
     try:
@@ -307,14 +1013,14 @@ def run_genesis4(inp, launcher, *args, **kwargs):
     inp_file = inp.inp_file
     inp_path = os.path.join(inp.exp_dir, inp.inp_file)
     # if inp.stageid is None:
-        # inp_path = inp.run_dir + 'run.' + str(inp.runid) + inp.suffix + '.inp'
-        # out_path = inp.run_dir + 'run.' + str(inp.runid) + inp.suffix + '.gout'
-        # inp.stageid = ''
-        # stage_string = ''
+    # inp_path = inp.run_dir + 'run.' + str(inp.runid) + inp.suffix + '.inp'
+    # out_path = inp.run_dir + 'run.' + str(inp.runid) + inp.suffix + '.gout'
+    # inp.stageid = ''
+    # stage_string = ''
     # else:
-        # inp_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + inp.suffix + '.inp'
-        # out_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + inp.suffix + '.gout'
-        # stage_string = '.s' + str(inp.stageid)
+    # inp_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + inp.suffix + '.inp'
+    # out_path = inp.run_dir + 'run.' + str(inp.runid) + '.s' + str(inp.stageid) + inp.suffix + '.gout'
+    # stage_string = '.s' + str(inp.stageid)
 
     # inp_file = filename_from_path(inp_path)
     # out_file = filename_from_path(out_path)
@@ -328,54 +1034,54 @@ def run_genesis4(inp, launcher, *args, **kwargs):
 
     # # create and fill necessary input files
     # if inp.latticefile == None:
-        # if inp.lat != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.lat')
-            # if not hasattr(inp, 'lat_unit'):
-                # lat_unit = inp.xlamd
-                # _logger.debug(2*ind_str + 'lat_unit_size = xlamds = {} m'.format(lat_unit))
-            # else:
-                # if inp.lat_unit is None:
-                    # lat_unit = inp.xlamd
-                    # _logger.debug(2*ind_str + 'lat_unit_size = xlamds = {} m'.format(lat_unit))
-                # else:
-                    # lat_unit = inp.lat_unit
-                    # _logger.debug(2*ind_str + 'lat_unit_size = {} m'.format(lat_unit))
-            # open(inp_path + '.lat', 'w').write(generate_lattice(inp.lat, unit=lat_unit, energy=inp.gamma0 * m_e_GeV, debug = debug, min_phsh = min_phsh))
-            # inp.latticefile = inp_file + '.lat'
+    # if inp.lat != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.lat')
+    # if not hasattr(inp, 'lat_unit'):
+    # lat_unit = inp.xlamd
+    # _logger.debug(2*ind_str + 'lat_unit_size = xlamds = {} m'.format(lat_unit))
+    # else:
+    # if inp.lat_unit is None:
+    # lat_unit = inp.xlamd
+    # _logger.debug(2*ind_str + 'lat_unit_size = xlamds = {} m'.format(lat_unit))
+    # else:
+    # lat_unit = inp.lat_unit
+    # _logger.debug(2*ind_str + 'lat_unit_size = {} m'.format(lat_unit))
+    # open(inp_path + '.lat', 'w').write(generate_lattice(inp.lat, unit=lat_unit, energy=inp.gamma0 * m_e_GeV, debug = debug, min_phsh = min_phsh))
+    # inp.latticefile = inp_file + '.lat'
 
     # if inp.beamfile == None:
-        # if inp.beam != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.beam')
-            # open(inp_path + '.beam', 'w').write(beam_file_str(inp.beam))
-            # inp.beamfile = inp_file + '.beam'
+    # if inp.beam != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.beam')
+    # open(inp_path + '.beam', 'w').write(beam_file_str(inp.beam))
+    # inp.beamfile = inp_file + '.beam'
 
     # if inp.edistfile == None:
-        # if inp.edist != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.edist')
-            # write_edist_file(inp.edist, inp_path + '.edist', debug=1)
-            # inp.edistfile = inp_file + '.edist'
+    # if inp.edist != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.edist')
+    # write_edist_file(inp.edist, inp_path + '.edist', debug=1)
+    # inp.edistfile = inp_file + '.edist'
 
     # if inp.partfile == None:
-        # if inp.dpa != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.dpa')
-            # # print ('!!!!!!! no write_particle_file() function')
-            # write_dpa_file(inp.dpa, inp_path + '.dpa', debug=1)
-            # inp.partfile = inp_file + '.dpa'
+    # if inp.dpa != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.dpa')
+    # # print ('!!!!!!! no write_particle_file() function')
+    # write_dpa_file(inp.dpa, inp_path + '.dpa', debug=1)
+    # inp.partfile = inp_file + '.dpa'
 
     # if inp.fieldfile == None:
-        # if inp.dfl != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.dfl')
-            # write_dfl_file(inp.dfl, inp_path + '.dfl', debug=1)
-            # inp.fieldfile = inp_file + '.dfl'
+    # if inp.dfl != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.dfl')
+    # write_dfl_file(inp.dfl, inp_path + '.dfl', debug=1)
+    # inp.fieldfile = inp_file + '.dfl'
 
     # if inp.radfile == None:
-        # if inp.rad != None:
-            # _logger.debug(ind_str + 'writing ' + inp_file + '.rad')
-            # open(inp_path + '.rad', 'w').write(rad_file_str(inp.rad))
-            # inp.radfile = inp_file + '.rad'
+    # if inp.rad != None:
+    # _logger.debug(ind_str + 'writing ' + inp_file + '.rad')
+    # open(inp_path + '.rad', 'w').write(rad_file_str(inp.rad))
+    # inp.radfile = inp_file + '.rad'
 
     # if inp.outputfile == None:
-        # inp.outputfile = out_file
+    # inp.outputfile = out_file
     _logger.debug(ind_str + 'writing ' + inp_file)
     open(inp_path, 'w').write(inp.input())
     # open(inp.run_dir + 'tmp.cmd', 'w').write(inp_file + '\n')
@@ -391,128 +1097,125 @@ def run_genesis4(inp, launcher, *args, **kwargs):
     # RUNNING GENESIS ###
 
     # if assembly_ver is not None:
-        # # genesis output slices assembly
-        # _logger.info(ind_str + 'assembling slices')
-        # _logger.debug(2 * ind_str + 'assembly_ver = {}'.format(assembly_ver))
-
-        # assembly_time = time.time()
-
-
-        # if assembly_ver == 'sys':
-
-            # _logger.info(2 * ind_str + 'assembling *.out file')
-            # start_time = time.time()
-            # os.system('cat ' + out_path + '.slice* >> ' + out_path)
-            # os.system('rm ' + out_path + '.slice* 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # _logger.info(2 * ind_str + 'assembling *.dfl file')
-            # start_time = time.time()
-            # if dfl_slipage_incl:
-                # os.system('cat ' + out_path + '.dfl.slice*  >> ' + out_path + '.dfl.tmp')
-                # #bytes=os.path.getsize(out_path +'.dfl.tmp')
-                # command = 'dd if=' + out_path + '.dfl.tmp of=' + out_path + '.dfl conv=notrunc conv=notrunc 2>/dev/null'# obs='+str(bytes)+' skip=1
-                # os.system(command)
-            # else:
-                # os.system('cat ' + out_path + '.dfl.slice*  > ' + out_path + '.dfl')
-            # os.system('rm ' + out_path + '.dfl.slice* 2>/dev/null')
-            # os.system('rm ' + out_path + '.dfl.tmp 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # _logger.info(2 * ind_str + 'assembling *.dpa file')
-            # start_time = time.time()
-            # os.system('cat ' + out_path + '.dpa.slice* >> ' + out_path + '.dpa')
-            # os.system('rm ' + out_path + '.dpa.slice* 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # _logger.info(2 * ind_str + 'assembling *.fld file')
-            # start_time = time.time()
-            # if dfl_slipage_incl:
-                # os.system('cat ' + out_path + '.fld.slice*  >> ' + out_path + '.fld.tmp')
-                # #bytes=os.path.getsize(out_path +'.fld.tmp')
-                # command = 'dd if=' + out_path + '.fld.tmp of=' + out_path + '.fld conv=notrunc conv=notrunc 2>/dev/null'# obs='+str(bytes)+' skip=1
-                # os.system(command)
-            # else:
-                # os.system('cat ' + out_path + '.fld.slice*  > ' + out_path + '.fld')
-            # os.system('rm ' + out_path + '.fld.slice* 2>/dev/null')
-            # os.system('rm ' + out_path + '.fld.tmp 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # _logger.info(2 * ind_str + 'assembling *.par file')
-            # start_time = time.time()
-            # os.system('cat ' + out_path + '.par.slice* >> ' + out_path + '.par')
-            # os.system('rm ' + out_path + '.par.slice* 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-        # elif assembly_ver == 'pyt':
-            # # there is a bug with dfl assembly
-            # import glob
-            # ram = 1
-
-            # _logger.info(2 * ind_str + 'assembling *.out file')
-            # start_time = time.time()
-            # assemble(out_path, ram=ram, debug=debug)
-            # os.system('rm ' + out_path + '.slice* 2>/dev/null')
-            # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # for i in range(10):        #read all possible harmonics (up to 10 now)
-                # ii=str(i)
-                # if ii=='0': ii=''
-                # if os.path.isfile(str(out_path + '.dfl' + ii)):
-                    # _logger.info(2 * ind_str + 'assembling *.dfl'+ii+' file')
-                    # start_time = time.time()
-                    # assemble(out_path + '.dfl'+ii, overwrite=dfl_slipage_incl, ram=ram, debug=debug)
-                    # os.system('rm ' + out_path + '.dfl'+ii+'.slice* 2>/dev/null')
-                    # os.system('rm ' + out_path + '.dfl'+ii+'.tmp 2>/dev/null')
-                    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # if os.path.isfile(str(out_path + '.dpa')):
-                # _logger.info(2 * ind_str + 'assembling *.dpa file')
-                # start_time = time.time()
-                # assemble(out_path + '.dpa', ram=ram, debug=debug)
-                # os.system('rm ' + out_path + '.dpa.slice* 2>/dev/null')
-                # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # if os.path.isfile(str(out_path + '.fld')):
-                # _logger.info(2 * ind_str + 'assembling *.fld file')
-                # start_time = time.time()
-                # assemble(out_path + '.fld', overwrite=dfl_slipage_incl, ram=ram, debug=debug)
-                # os.system('rm ' + out_path + '.fld.slice* 2>/dev/null')
-                # os.system('rm ' + out_path + '.fld.tmp 2>/dev/null')
-                # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-            # if os.path.isfile(str(out_path + '.par')):
-                # _logger.info(2 * ind_str + 'assembling *.par file')
-                # start_time = time.time()
-                # assemble(out_path + '.par', ram=ram, debug=debug)
-                # os.system('rm ' + out_path + '.par.slice* 2>/dev/null')
-                # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
-        # else:
-            # # raise ValueError('assembly_ver should be either "sys" or "pyt"')
-            # pass
-        # _logger.debug(2 * ind_str + 'assembly time %.2f seconds' % (time.time() - assembly_time))
-
+    # # genesis output slices assembly
+    # _logger.info(ind_str + 'assembling slices')
+    # _logger.debug(2 * ind_str + 'assembly_ver = {}'.format(assembly_ver))
+
+    # assembly_time = time.time()
+
+    # if assembly_ver == 'sys':
+
+    # _logger.info(2 * ind_str + 'assembling *.out file')
+    # start_time = time.time()
+    # os.system('cat ' + out_path + '.slice* >> ' + out_path)
+    # os.system('rm ' + out_path + '.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # _logger.info(2 * ind_str + 'assembling *.dfl file')
+    # start_time = time.time()
+    # if dfl_slipage_incl:
+    # os.system('cat ' + out_path + '.dfl.slice*  >> ' + out_path + '.dfl.tmp')
+    # #bytes=os.path.getsize(out_path +'.dfl.tmp')
+    # command = 'dd if=' + out_path + '.dfl.tmp of=' + out_path + '.dfl conv=notrunc conv=notrunc 2>/dev/null'# obs='+str(bytes)+' skip=1
+    # os.system(command)
+    # else:
+    # os.system('cat ' + out_path + '.dfl.slice*  > ' + out_path + '.dfl')
+    # os.system('rm ' + out_path + '.dfl.slice* 2>/dev/null')
+    # os.system('rm ' + out_path + '.dfl.tmp 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # _logger.info(2 * ind_str + 'assembling *.dpa file')
+    # start_time = time.time()
+    # os.system('cat ' + out_path + '.dpa.slice* >> ' + out_path + '.dpa')
+    # os.system('rm ' + out_path + '.dpa.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # _logger.info(2 * ind_str + 'assembling *.fld file')
+    # start_time = time.time()
+    # if dfl_slipage_incl:
+    # os.system('cat ' + out_path + '.fld.slice*  >> ' + out_path + '.fld.tmp')
+    # #bytes=os.path.getsize(out_path +'.fld.tmp')
+    # command = 'dd if=' + out_path + '.fld.tmp of=' + out_path + '.fld conv=notrunc conv=notrunc 2>/dev/null'# obs='+str(bytes)+' skip=1
+    # os.system(command)
+    # else:
+    # os.system('cat ' + out_path + '.fld.slice*  > ' + out_path + '.fld')
+    # os.system('rm ' + out_path + '.fld.slice* 2>/dev/null')
+    # os.system('rm ' + out_path + '.fld.tmp 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # _logger.info(2 * ind_str + 'assembling *.par file')
+    # start_time = time.time()
+    # os.system('cat ' + out_path + '.par.slice* >> ' + out_path + '.par')
+    # os.system('rm ' + out_path + '.par.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # elif assembly_ver == 'pyt':
+    # # there is a bug with dfl assembly
+    # import glob
+    # ram = 1
+
+    # _logger.info(2 * ind_str + 'assembling *.out file')
+    # start_time = time.time()
+    # assemble(out_path, ram=ram, debug=debug)
+    # os.system('rm ' + out_path + '.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # for i in range(10):        #read all possible harmonics (up to 10 now)
+    # ii=str(i)
+    # if ii=='0': ii=''
+    # if os.path.isfile(str(out_path + '.dfl' + ii)):
+    # _logger.info(2 * ind_str + 'assembling *.dfl'+ii+' file')
+    # start_time = time.time()
+    # assemble(out_path + '.dfl'+ii, overwrite=dfl_slipage_incl, ram=ram, debug=debug)
+    # os.system('rm ' + out_path + '.dfl'+ii+'.slice* 2>/dev/null')
+    # os.system('rm ' + out_path + '.dfl'+ii+'.tmp 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # if os.path.isfile(str(out_path + '.dpa')):
+    # _logger.info(2 * ind_str + 'assembling *.dpa file')
+    # start_time = time.time()
+    # assemble(out_path + '.dpa', ram=ram, debug=debug)
+    # os.system('rm ' + out_path + '.dpa.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # if os.path.isfile(str(out_path + '.fld')):
+    # _logger.info(2 * ind_str + 'assembling *.fld file')
+    # start_time = time.time()
+    # assemble(out_path + '.fld', overwrite=dfl_slipage_incl, ram=ram, debug=debug)
+    # os.system('rm ' + out_path + '.fld.slice* 2>/dev/null')
+    # os.system('rm ' + out_path + '.fld.tmp 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+
+    # if os.path.isfile(str(out_path + '.par')):
+    # _logger.info(2 * ind_str + 'assembling *.par file')
+    # start_time = time.time()
+    # assemble(out_path + '.par', ram=ram, debug=debug)
+    # os.system('rm ' + out_path + '.par.slice* 2>/dev/null')
+    # _logger.debug(3 * ind_str + 'done in %.2f seconds' % (time.time() - start_time))
 
+    # else:
+    # # raise ValueError('assembly_ver should be either "sys" or "pyt"')
+    # pass
+    # _logger.debug(2 * ind_str + 'assembly time %.2f seconds' % (time.time() - assembly_time))
 
     # if read_level >= 0:
-        # out = read_out_file(out_path, read_level=read_level)
-        # _logger.debug(ind_str + 'done, time %.2f seconds' % (time.time() - assembly_time))
-        # return out
+    # out = read_out_file(out_path, read_level=read_level)
+    # _logger.debug(ind_str + 'done, time %.2f seconds' % (time.time() - assembly_time))
+    # return out
     # else:
-        # _logger.debug(ind_str + 'done, time %.2f seconds' % (time.time() - assembly_time))
-        # return None
+    # _logger.debug(ind_str + 'done, time %.2f seconds' % (time.time() - assembly_time))
+    # return None
     return
 
 
 def read_gout4(filePath):
-    '''
+    """
     Reads Genesis1.3 v4 output file with the link to the hdf5 file as out.h5
     to close the file, use out.h5.close()
     
     :param filePath: string, absolute path to .out file
     :returns: Genesis4Output
-    '''
+    """
 
     _logger.info('reading gen4 .out file')
     _logger.warning(ind_str + 'in beta')
@@ -525,15 +1228,18 @@ def read_gout4(filePath):
         _logger.error(ind_str + 'no such file ' + filePath)
         raise
 
-    vvv = [int(out.h5['Meta/Version/'+name][0]) for name in ['Major', 'Minor', 'Revision']]
+    if not ('Global' and 'Lattice' in out.h5):
+        _logger.warning('Not a valid .out file')
+
+    vvv = [int(out.h5['Meta/Version/' + name][0]) for name in ['Major', 'Minor', 'Revision']]
     _logger.debug(ind_str + 'Genesis v{}.{}.{}'.format(*vvv))
 
     out.z = out.h5['Lattice/zplot'][:]
     out.zlat = out.h5['Lattice/z'][:]
 
     _logger.debug(ind_str + 'z[0]   , z[-1]   , len(z)    = {}  {}  {}'.format(out.z[0], out.z[-1], len(out.z)))
-    _logger.debug(ind_str + 'zlat[0], zlat[-1], len(zlat) = {}  {}  {}'.format(out.zlat[0], out.zlat[-1], len(out.zlat)))
-
+    _logger.debug(
+        ind_str + 'zlat[0], zlat[-1], len(zlat) = {}  {}  {}'.format(out.zlat[0], out.zlat[-1], len(out.zlat)))
 
     if 'time' in out.h5['Global'] and out.h5['Global/time'][0] == 1:
         out.tdp = True
@@ -542,6 +1248,9 @@ def read_gout4(filePath):
         out.tdp = False
         _logger.debug(ind_str + 'tdp = False')
 
+    if not out.tdp and out.h5['Beam/current'].size > 1:  # same as out.nSlices > 1:
+        _logger.error('time independent simulation with {} slices'.format(out.nSlices))
+
     if out.tdp:
         if 's0' in out.h5['Global']:
             s0 = out.h5['Global/s0']
@@ -549,20 +1258,21 @@ def read_gout4(filePath):
         else:
             s0 = 0
         sn = out.h5['Beam/current'].size
-        out.s = np.linspace(s0, out.h5['Global/slen'][:][0]+s0, sn)
+        out.s = np.linspace(s0, out.h5['Global/slen'][:][0] + s0, sn)
         _logger.debug(ind_str + 's[0], s[-1], len(s) = {}  {}  {}'.format(out.s[0], out.s[-1], sn))
 
     _logger.debug(ind_str + 'done')
 
     return out
 
+
 def read_dfl4(filePath):
-    '''
+    """
     Reads Genesis1.3 v4 radiation output file
     
     :param filePath: string, absolute path to .fld file
     :returns: RadiationField
-    '''
+    """
     _logger.info('reading gen4 .dfl file')
     _logger.warning(ind_str + 'in beta')
     _logger.debug(ind_str + 'reading from ' + filePath)
@@ -577,7 +1287,7 @@ def read_dfl4(filePath):
             ncar = h5.get('gridpoints')[0]
         except:
             # legacy support
-            ncar = int(np.sqrt(h5.get('slice000001/field-real').size)) # fix?
+            ncar = int(np.sqrt(h5.get('slice000001/field-real').size))  # fix?
         zsep = int(sepslice / lambdaref)
         l_total = sepslice * nslice
 
@@ -588,7 +1298,7 @@ def read_dfl4(filePath):
         _logger.debug(ind_str + '')
         _logger.debug(ind_str + 'zsep = {}'.format(zsep))
         _logger.debug(ind_str + 'Nx & Ny = {}'.format(ncar))
-        _logger.debug(ind_str + 'Lx & Ly = {}'.format(ncar*gridsize))
+        _logger.debug(ind_str + 'Lx & Ly = {}'.format(ncar * gridsize))
         _logger.debug(ind_str + 'Ls_total = {}'.format(l_total))
 
         field_real = []
@@ -662,22 +1372,23 @@ def write_dfl4(dfl: RadiationField, file_path='sample.dfl.h5'):
         except:
             h5.create_dataset('refposition', data=[0.0])
 
-
         for i in range(dfl.Nz()):
-            _logger.log(5, 'slice{:06d}'.format(i+1))
-            h5.create_dataset('slice{:06d}/field-real'.format(i+1), data=np.real(dfl.fld[i]).flatten())
-            h5.create_dataset('slice{:06d}/field-imag'.format(i+1), data=np.imag(dfl.fld[i]).flatten())
+            _logger.log(5, 'slice{:06d}'.format(i + 1))
+            h5.create_dataset('slice{:06d}/field-real'.format(i + 1), data=np.real(dfl.fld[i]).flatten())
+            h5.create_dataset('slice{:06d}/field-imag'.format(i + 1), data=np.imag(dfl.fld[i]).flatten())
 
     _logger.debug(ind_str + 'done')
 
 
-def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
-    '''
+def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0, partskip=1):
+    """
     Reads Genesis1.3 v4 particle output file
     
     :param filePath: string, absolute path to .par file
+    :partskip: int, allows to read every nth particle only to save space. (default=1)
+    :estimate_npart: reads the header and estimates number of particles and type of simulation. 0 - no estimation. 1 - normal estimation with console output. 2 - estimation only, omitting the actual parsing of particles
     :returns: Genesis4ParticlesDump
-    '''
+    """
 
     _logger.info('reading gen4 .dpa file')
     _logger.warning(ind_str + 'in beta')
@@ -686,7 +1397,12 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
     start_time = time.time()
 
     _logger.debug(ind_str + 'start_slice : stop_slice = {} : {}'.format(start_slice, stop_slice))
-
+    
+    sl = slice(None, None, partskip)
+    
+    if partskip > 1:
+        _logger.debug(ind_str + 'reading every {}st/th particle'.format(partskip))
+    
     with h5py.File(filePath, 'r') as h5:
 
         one4one = bool(h5.get('one4one')[0])
@@ -698,30 +1414,33 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
         sepslice = h5.get('slicespacing')[0]
 
         if not one4one:
-            npart = int(h5.get('slice000001/gamma').size) # fix?
+            npart = int(h5.get('slice000001/gamma').size)  # fix?
             _logger.debug(ind_str + 'npart = {}'.format(npart))
         else:
-            if estimate_npart:
+            if estimate_npart > 0:
                 I_tmp_full = []
                 I_tmp_wind = []
                 for dset in h5:
                     if dset.startswith('slice') and type(h5[dset]) == h5py._hl.group.Group:
-                        slice = int(dset.replace('slice',''))
+                        slicen = int(dset.replace('slice', ''))
                         I_tmp_full.append(h5[dset]['current'][:])
-                        if slice >= start_slice and slice <= stop_slice:
+                        if slicen >= start_slice and slicen <= stop_slice:
                             I_tmp_wind.append(h5[dset]['current'][:])
                 npart_full_tmp = np.sum(I_tmp_full) * lslice / speed_of_light / q_e
                 npart_wind_tmp = np.sum(I_tmp_wind) * lslice / speed_of_light / q_e
-                _logger.info(ind_str + 'estimated npart = {:}M'.format(npart_full_tmp/1e6))
-                _logger.info(ind_str + 'estimated npart to be downloaded = {:}.M'.format(npart_wind_tmp/1e6))
-
+                _logger.info(ind_str + 'estimated npart = {:}M'.format(npart_full_tmp / 1e6))
+                _logger.info(ind_str + 'estimated npart to be downloaded = {:}.M'.format(npart_wind_tmp / partskip / 1e6))
 
         # filePath = h5.filename
 
         zsep = int(sepslice / lslice)
-        l_total = lslice * zsep * nslice
-
-
+        # if one4one:
+            # l_total = lslice * nslice
+        # else:
+            # l_total = lslice * zsep * nslice
+        l_total = sepslice * nslice
+        
+        
         _logger.debug(ind_str + 'nslice = {}'.format(nslice))
         _logger.debug(ind_str + 'nbins = {}'.format(nbins))
         _logger.debug(ind_str + '')
@@ -729,7 +1448,28 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
         _logger.debug(ind_str + 'sepslice = {} m'.format(sepslice))
         _logger.debug(ind_str + 'zsep = {}'.format(zsep))
         _logger.debug(ind_str + 'Ls_total = {}'.format(l_total))
-
+        
+        dpa = Genesis4ParticlesDump()
+        dpa.nslice = nslice
+        dpa.lslice = lslice
+        dpa.sepslice = sepslice
+        dpa.nbins = nbins
+        dpa.zsep = zsep
+        dpa.filePath = filePath
+        dpa.one4one = one4one
+        
+        _logger.debug(ind_str + 'nslice = {}'.format(nslice))
+        _logger.debug(ind_str + 'nbins = {}'.format(nbins))
+        _logger.debug(ind_str + 'lslice (aka xlamds) = {} m'.format(lslice))
+        _logger.debug(ind_str + 'sepslice = {} m'.format(sepslice))
+        _logger.debug(ind_str + 'zsep = {}'.format(zsep))
+        _logger.debug(ind_str + 'Ls_total = {}'.format(l_total))
+        
+        if estimate_npart == 2:
+            _logger.debug(ind_str + 'done in %.2f seconds' % (time.time() - start_time))
+            return dpa
+            
+        
         x = []
         y = []
         px = []
@@ -740,35 +1480,39 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
         # s = []
         I = []
         npartpb = []
+        slicenum = [] #slice where the particle belongs
+        slicelist = []
 
         _logger.debug(ind_str + 'reading slices between {} and {}'.format(start_slice, stop_slice))
-        _logger.debug(2*ind_str + '({} out of {})'.format(stop_slice - start_slice, nslice))
+        _logger.debug(2 * ind_str + '({} out of {})'.format(stop_slice - start_slice, nslice))
         for dset in sorted(h5):
             # _logger.log(5, ind_str + dset)
             # _logger.log(5, ind_str + str(type(h5[dset])))
             if dset.startswith('slice') and type(h5[dset]) == h5py._hl.group.Group:
-                slice = int(dset.replace('slice',''))
-                _logger.log(5, 2*ind_str + 'slice number {}'.format(slice))
-                if slice >= start_slice and slice <= stop_slice:
-                    _logger.log(5, 2*ind_str + 'processing')
+                slicen = int(dset.replace('slice', ''))
+                _logger.log(5, 2 * ind_str + 'slice number {}'.format(slicen))
+                if slicen >= start_slice and slicen <= stop_slice:
+                    _logger.log(5, 2 * ind_str + 'processing')
                     I.append(h5[dset]['current'][:])
-                    ph.append(h5[dset]['theta'][:])
-                    _logger.log(5, 2*ind_str + '{} particles'.format(h5[dset]['x'].size))
+                    ph.append(h5[dset]['theta'][sl])
+                    _logger.log(5, 2 * ind_str + '{} particles'.format(h5[dset]['x'].size))
                     # s.append(s0 + ph0 / 2 / np.pi * lslice)
-                    x.append(h5[dset]['x'][:])
-                    px.append(h5[dset]['px'][:])
-                    y.append(h5[dset]['y'][:])
-                    py.append(h5[dset]['py'][:])
-                    g.append(h5[dset]['gamma'][:])
-                    npartpb.append(h5[dset]['gamma'][:].size)
+                    x.append(h5[dset]['x'][sl])
+                    px.append(h5[dset]['px'][sl])
+                    y.append(h5[dset]['y'][sl])
+                    py.append(h5[dset]['py'][sl])
+                    g.append(h5[dset]['gamma'][sl])
+                    npartpbi = h5[dset]['gamma'][sl].size
+                    npartpb.append(npartpbi)
+                    slicenum.extend(list(np.ones(npartpbi, dtype=int)*slicen))
+                    slicelist.append(slicen)
                     # ph.append(ph0)
                     # s0 += sepslice
-        _logger.debug(2*ind_str + 'done')
-
-    dpa = Genesis4ParticlesDump()
-
+        _logger.debug(2 * ind_str + 'done')
+    
     if one4one:
         _logger.debug(ind_str + 'flattening arrays')
+        _logger.debug(ind_str + 'writing to dpa object')
         # _logger.log(5, 2*ind_str + 'x.shape {}'.format(np.shape(x)))
         dpa.x = np.hstack(x)
         dpa.px = np.hstack(px)
@@ -777,26 +1521,31 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
         dpa.g = np.hstack(g)
         dpa.I = np.hstack(I)
         dpa.ph = np.hstack(ph)
-        _logger.log(5, 2*ind_str + 'dpa.x.shape {}'.format(dpa.x.shape))
+        dpa.slicenum = np.array(slicenum)
+        
+        _logger.log(5, 2 * ind_str + 'dpa.x.shape {}'.format(dpa.x.shape))
 
         dpa.npartpb = np.array(npartpb).flatten()
 
         npart = dpa.x.size
         _logger.info(ind_str + 'npart = {}'.format(npart))
+        
+        dpa.one4one_qp = q_e * partskip #particle charge, assuming that npart(original) >> partskip
     else:
-        npartpb = int(npart/nbins)
+        npartpb = int(npart / nbins)
         # _logger.debug(ind_str + 'not one4one:')
-        _logger.debug(2*ind_str + 'shape of arrays (nslice, npart) {}'.format(np.array(x).shape))
+        _logger.debug(2 * ind_str + 'shape of arrays (nslice, npart) {}'.format(np.array(x).shape))
 
         if np.array(x).shape[0] < nslice:
             nslice = np.array(x).shape[0]
 
         if nslice == 0:
-            _logger.error(2*ind_str + 'nslice == 0')
+            _logger.error(2 * ind_str + 'nslice == 0')
             return
 
-        _logger.debug(2*ind_str + 'reshaping to (nslice, nbins, npart/bin) ({}, {}, {})'.format(nslice, nbins, npartpb))
-
+        _logger.debug(
+            2 * ind_str + 'reshaping to (nslice, nbins, npart/bin) ({}, {}, {})'.format(nslice, nbins, npartpb))
+        _logger.debug(ind_str + 'writing to dpa object')
         dpa.x = np.array(x).reshape((nslice, nbins, npartpb), order='F')
         dpa.px = np.array(px).reshape((nslice, nbins, npartpb), order='F')
         dpa.y = np.array(y).reshape((nslice, nbins, npartpb), order='F')
@@ -804,47 +1553,38 @@ def read_dpa4(filePath, start_slice=0, stop_slice=np.inf, estimate_npart=0):
         dpa.ph = np.array(ph).reshape((nslice, nbins, npartpb), order='F')
         dpa.g = np.array(g).reshape((nslice, nbins, npartpb), order='F')
         dpa.I = np.array(I).flatten()
-
-    _logger.debug(ind_str + 'writing to dpa object')
-    dpa.nslice = nslice
-    dpa.lslice = lslice
+    
+    
     dpa.npart = npart
-    dpa.nbins = nbins
-    dpa.zsep = zsep
-    dpa.filePath = filePath
-    dpa.one4one = one4one
+    dpa.slicelist = np.array(slicelist)
 
     _logger.debug(ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
+    
     return dpa
 
 
-
-
-
 def dpa42edist(dpa, n_part=None, fill_gaps=False):
-    '''
+    """
     Convert Genesis1.3 v4 particle output file to ocelot edist object
     
     :param dpa: GenesisParticlesDump
     :param n_part: desired approximate number of particles in edist
     :param fill_gaps: dublicates buckets into gaps
     :returns: GenesisElectronDist
-    '''
+    """
 
     _logger.info('converting dpa4 to edist')
     _logger.warning(ind_str + 'in beta')
 
     # if dpa.one4one is True:
-        # _logger.warning(ind_str + 'not tested for one4one yet')
-        # return
+    # _logger.warning(ind_str + 'not tested for one4one yet')
+    # return
     if dpa.one4one is None:
         _logger.error(ind_str + 'unknown one4one status')
         return
 
     # fill_gaps=False #unfinished
 
-
     import random
     start_time = time.time()
 
@@ -865,12 +1605,13 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
     _logger.debug(ind_str + 'fill_gaps = {}'.format(fill_gaps))
 
     if dpa.one4one:
-        t0 = np.hstack([np.ones(n)*i for i, n in enumerate(dpa.npartpb)]) * dpa.lslice / speed_of_light
-        t0 += dpa.ph / 2 / np.pi * dpa.lslice / speed_of_light
+        t0 = np.hstack([np.ones(n) * i for i, n in enumerate(dpa.npartpb)]) * dpa.sepslice / speed_of_light
+        t0 += dpa.ph / 2 / np.pi * dpa.sepslice / speed_of_light
 
         edist = GenesisElectronDist()
 
-        C = npart * q_e
+        #C = npart * q_e
+        C = npart * dpa.one4one_qp
 
         if n_part is not None:
             pick_i = random.sample(range(npart), n_part)
@@ -881,7 +1622,6 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
             n_part = npart
             # particles_kept_ratio = 1
 
-
         _logger.debug(ind_str + 'particles kept = {}%'.format(n_part / npart * 100))
         _logger.debug(ind_str + 'picking {} of {} particles'.format(len(pick_i), npart))
 
@@ -900,15 +1640,15 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
             edist.y = dpa.y[pick_i]
             edist.t = t0[pick_i]
 
-        _logger.debug(2*ind_str + 'done')
+        _logger.debug(2 * ind_str + 'done')
 
     else:
         # if fill_gaps:
 
-            # s0 = np.linspace(0, nslice * zsep * lslice, nslice)
-            # s = np.linspace(0, nslice * zsep * lslice, nslice * zsep)
-            # I = np.interp(s, s0, dpa.I)
-            # dt = (s[1] - s[0]) / speed_of_light
+        # s0 = np.linspace(0, nslice * zsep * lslice, nslice)
+        # s = np.linspace(0, nslice * zsep * lslice, nslice * zsep)
+        # I = np.interp(s, s0, dpa.I)
+        # dt = (s[1] - s[0]) / speed_of_light
         # else:
         s = np.linspace(0, nslice * zsep * lslice, nslice)
         I = dpa.I
@@ -932,21 +1672,17 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
             _logger.info(ind_str + 'requested n_part = None, setting to maximum = {}'.format(n_part_max))
             n_part = n_part_max
 
-
-
-        #n_part_bin = (I / np.sum(I) * n_part / nbins).astype(int)
-        #n_part_bin[n_part_bin > npart_bin] = npart_bin
-        #print(n_part_bin.max())
+        # n_part_bin = (I / np.sum(I) * n_part / nbins).astype(int)
+        # n_part_bin[n_part_bin > npart_bin] = npart_bin
+        # print(n_part_bin.max())
         n_part_slice = (I / np.sum(I) * n_part).astype(int)
         n_part_slice[n_part_slice > npart] = npart
 
         _logger.debug(ind_str + 'max particles/slice = {}'.format(n_part_slice.max()))
 
-
         # print(n_part_slice.max())
 
-
-        #pick_i = random.sample(range(n_part), n_part_slice[i])
+        # pick_i = random.sample(range(n_part), n_part_slice[i])
         # _logger.debug(ind_str + 'reshaping')
 
         # g = np.reshape(dpa.g, (nslice, npart))
@@ -956,7 +1692,6 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
         # py = np.reshape(dpa.py, (nslice, npart)) / g
         # ph = np.reshape(dpa.ph, (nslice, npart))
 
-
         g = dpa.g.reshape(nslice, npart)
         x = dpa.x.reshape(nslice, npart)
         y = dpa.y.reshape(nslice, npart)
@@ -965,16 +1700,15 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
         ph = dpa.ph.reshape(nslice, npart)
 
         t1 = ph / 2 / np.pi * lslice / speed_of_light
-        t0 = np.arange(nslice)[:,np.newaxis] * lslice * zsep / speed_of_light
+        t0 = np.arange(nslice)[:, np.newaxis] * lslice * zsep / speed_of_light
 
-        t = t1+t0
+        t = t1 + t0
         # _logger.debug(2*ind_str + 'complete')
 
-
         edist = GenesisElectronDist()
-        #g1 = np.array([])
-        #x1 = np.array([])
-        #y1 = np.array([])
+        # g1 = np.array([])
+        # x1 = np.array([])
+        # y1 = np.array([])
 
         gi = []
         xpi = []
@@ -985,64 +1719,70 @@ def dpa42edist(dpa, n_part=None, fill_gaps=False):
 
         _logger.debug(ind_str + 'picking random particles')
         for i in np.arange(nslice):
-        #    for ii in np.arange(nbins):
-        #    pick_i = random.sample(range(npart_bin), n_part_bin[i])
+            #    for ii in np.arange(nbins):
+            #    pick_i = random.sample(range(npart_bin), n_part_bin[i])
             pick_i = random.sample(range(npart), n_part_slice[i])
-
-
+            _logger.log(5, "slice {} pick {} from {}".format(i, n_part_slice[i], npart))
+            # _logger.log(1, "  {}".format(str(pick_i)))
             # edist.g = np.append(edist.g, g[i, pick_i])
             # edist.xp = np.append(edist.xp, px[i, pick_i])
             # edist.yp = np.append(edist.yp, py[i, pick_i])
             # edist.x = np.append(edist.x, x[i, pick_i])  
             # edist.y = np.append(edist.y, y[i, pick_i])
             # edist.t = np.append(edist.t, t[i, pick_i])
-
-            gi.append(g[i, pick_i])
-            xpi.append(px[i, pick_i])
-            ypi.append(py[i, pick_i])
-            xi.append(x[i, pick_i])
-            yi.append(y[i, pick_i])
-            ti.append(t[i, pick_i])
-
-        edist.g = np.array(gi).flatten()
-        edist.xp = np.array(xpi).flatten()
-        edist.yp = np.array(ypi).flatten()
-        edist.x = np.array(xi).flatten()
-        edist.y = np.array(yi).flatten()
-        edist.t = np.array(ti).flatten()
+            _logger.log(5, "  shape before: {}".format(str(g.shape)))
+            _logger.log(5, "  picking g[{}, len({})]".format(i, len(pick_i)))
+            _logger.log(5, "  shape after: {}".format(str(np.shape(g[i, pick_i]))))
+
+            gi.extend(g[i, pick_i])
+            xpi.extend(px[i, pick_i])
+            ypi.extend(py[i, pick_i])
+            xi.extend(x[i, pick_i])
+            yi.extend(y[i, pick_i])
+            ti.extend(t[i, pick_i])
+
+            _logger.log(5, "  shape after append: {}".format(str(len(gi))))
+
+        edist.g = np.array(gi)  # .flatten()
+        edist.xp = np.array(xpi)  # .flatten()
+        edist.yp = np.array(ypi)  # .flatten()
+        edist.x = np.array(xi)  # .flatten()
+        edist.y = np.array(yi)  # .flatten()
+        edist.t = np.array(ti)  # .flatten()
+        _logger.log(5, "  shape after flattening: {}".format(str(edist.g.shape)))
 
         if fill_gaps:
+            _logger.info(ind_str + 'randomly distributing particles in time between buckets')
             edist.t += np.random.randint(0, dpa.zsep, edist.t.size) * lslice / speed_of_light
 
-
         # particles_kept_ratio = 1
 
     edist.part_charge = C / edist.len()
     _logger.debug('')
 
     _logger.debug(ind_str + 'edist bunch charge = {} C'.format(C))
-    _logger.debug(ind_str + 'edist particle charge = {} C (~{:.2f}*q_e)'.format(edist.part_charge,edist.part_charge/q_e))
+    _logger.debug(
+        ind_str + 'edist particle charge = {} C (~{:.2f}*q_e)'.format(edist.part_charge, edist.part_charge / q_e))
     _logger.debug(ind_str + 'edist n_part = {}'.format(edist.len()))
 
-    if hasattr(dpa,'filePath'):
+    if hasattr(dpa, 'filePath'):
         edist.filePath = dpa.filePath + '.edist'
 
     _logger.debug(ind_str + 'done')
 
     return edist
 
-def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
 
+def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
     _logger.info('reading gen4 .dpa file into parray')
-    _logger.warning(ind_str + 'in beta')
+    _logger.warning(ind_str + 'in beta, fix situation with harmonic jump resulting in sepslice > lslice')
     _logger.debug(ind_str + 'reading from ' + filePath)
 
-
     import random
     N_part = None
 
-    #N_part = 100000
-    fill_gaps=True
+    # N_part = 100000
+    fill_gaps = True
     _logger.debug('fill_gaps = ' + str(fill_gaps))
 
     h5 = h5py.File(filePath, 'r')
@@ -1061,21 +1801,22 @@ def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
 
     _logger.debug('nslice = ' + str(nslice))
     _logger.debug('lslice = ' + str(lslice) + 'm')
-    _logger.debug('sepslice = ' + str(sepslice)+'m')
+    _logger.debug('sepslice = ' + str(sepslice) + 'm')
     _logger.debug('zsep = ' + str(zsep))
     _logger.debug('npart = ' + str(npart))
     _logger.debug('nbins = ' + str(nbins))
 
     I = []
     for dset in h5:
-            if dset.startswith('slice0'):
-                I.append(h5[dset]['current'][0])
+        if dset.startswith('slice0'):
+            I.append(h5[dset]['current'][0])
     I = np.array(I)
 
     dt = zsep * lslice / speed_of_light
     _logger.debug('dt = ' + str(dt) + 'sec')
 
-    N_part_max = np.sum(I / I.max() * npart) # total maximum reasonable number of macroparticles of the same charge that can be extracted
+    N_part_max = np.sum(
+        I / I.max() * npart)  # total maximum reasonable number of macroparticles of the same charge that can be extracted
 
     if N_part is not None:
         if N_part > N_part_max:
@@ -1084,15 +1825,15 @@ def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
         N_part = int(np.floor(N_part_max))
     _logger.debug('Number of particles max= ' + str(N_part))
 
-    n_part_slice = (I / np.sum(I) * N_part).astype(int) #array of number of particles per new bin
+    n_part_slice = (I / np.sum(I) * N_part).astype(int)  # array of number of particles per new bin
     n_part_slice[n_part_slice > npart] = npart
 
-    N_part_act = np.sum(n_part_slice) #actual number of particles
+    N_part_act = np.sum(n_part_slice)  # actual number of particles
     _logger.debug('Number of particles actual= ' + str(N_part_act))
 
     dt = zsep * lslice / speed_of_light
-    C = np.sum(I) * dt #total charge
-    c = C / N_part_act # particle charge
+    C = np.sum(I) * dt  # total charge
+    c = C / N_part_act  # particle charge
 
     pick_i = [random.sample(range(npart), n_part_slice[i]) for i in range(nslice)]
 
@@ -1106,10 +1847,10 @@ def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
 
     for dset in h5:
         if dset.startswith('slice0'):
-            i = int(dset.strip('/slice'))-1
+            i = int(dset.strip('/slice')) - 1
             if len(pick_i[i]) > 0:
                 ph0 = h5[dset]['theta'].value[pick_i[i]]
-                s.append(i*zsep*lslice + ph0 / 2 / np.pi * lslice)
+                s.append(i * zsep * lslice + ph0 / 2 / np.pi * lslice)
                 x.append(np.array(h5[dset]['x'].value[pick_i[i]]))
                 px.append(np.array(h5[dset]['px'].value[pick_i[i]]))
                 y.append(np.array(h5[dset]['y'].value[pick_i[i]]))
@@ -1120,13 +1861,13 @@ def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
     p_array.rparticles = np.empty((6, N_part_act))
 
     g = np.concatenate(g).ravel()
-    g0 = np.mean(g) # average gamma
-    p_array.E = g0 * m_e_GeV # average energy in GeV
-    p0 = sqrt(g0**2-1) * m_e_eV / speed_of_light
+    g0 = np.mean(g)  # average gamma
+    p_array.E = g0 * m_e_GeV  # average energy in GeV
+    p0 = np.sqrt(g0 ** 2 - 1) * m_e_eV / speed_of_light
 
-    p_array.rparticles[0] = np.concatenate(x).ravel() # position in x in meters
+    p_array.rparticles[0] = np.concatenate(x).ravel()  # position in x in meters
     p_array.rparticles[1] = np.concatenate(px).ravel() / g0  # divergence in x
-    p_array.rparticles[2] = np.concatenate(y).ravel() # position in x in meters
+    p_array.rparticles[2] = np.concatenate(y).ravel()  # position in x in meters
     p_array.rparticles[3] = np.concatenate(py).ravel() / g0  # divergence in x
     p_array.rparticles[4] = -np.concatenate(s).ravel()
     p_array.rparticles[5] = (g - g0) * m_e_eV / p0 / speed_of_light
@@ -1140,83 +1881,105 @@ def read_dpa42parray(filePath, N_part=None, fill_gaps=True):
     return p_array
 
 
-def write_gen4_lat(lat, filePath, line_name='LINE', l=np.inf):
-    from ocelot.cpbd.elements import Undulator, Drift, Quadrupole, UnknownElement
-    _logger.info('writing genesis4 lattice')
-    _logger.debug(ind_str + 'writing to ' + filePath)
-
-    lat_str = []
-    beamline = []
-    ll=0
-
-    lat_str.append('# generated with Ocelot\n')
-
-    for element in lat.sequence:
-
-        if ll >= l:
-            break
-
-        element_num = str(len(beamline) + 1).zfill(3)
-
-        if hasattr(element,'l'):
-            ll += element.l
-
-        if isinstance(element, Undulator):
-            element_name = element_num + 'UND'
-            s = '{:}: UNDULATOR = {{lambdau = {:}, nwig = {:}, aw = {:.6f}}};'.format(element_name, element.lperiod, element.nperiods, element.Kx/sqrt(2))
-#            print(s)
-
-        elif isinstance(element, Drift):
-            element_name = element_num + 'DR'
-            s = '{:}: DRIFT = {{l={:}}};'.format(element_name, element.l)
-
-        elif isinstance(element, Quadrupole):
-            if element.k1>=0:
-                element_name = element_num + 'QF'
-            else:
-                element_name =  element_num + 'QD'
-            s = '{:}: QUADRUPOLE = {{l = {:}, k1 = {:.6f} }};'.format(element_name, element.l, element.k1)
-
-        else:
-            _logger.debug('Unknown element with length '+ str(element.l))
-            continue
-
-        beamline.append(element_name)
-        lat_str.append(s)
-
-    lat_str.append('')
-    lat_str.append('{:}: LINE = {{{:}}};'.format(line_name, ','.join(beamline)))
-    lat_str.append('\n# end of file\n')
-
-    with open(filePath, 'w') as f:
-        f.write("\n".join(lat_str))
-
-def write_edist_hdf5(edist, filepath):
+# MOVE TO BEAM
+def write_edist_hdf5(edist, filepath, exist_ok=True):
+    _logger.info('writing electron distribution to {}'.format(filepath))
+    os.makedirs(filepath[:filepath.rindex(os.path.sep)], exist_ok=True)
     with h5py.File(filepath, 'w') as h5:
-        # h5 = h5py.File(filepath, 'w')
         h5.create_dataset('p', data=edist.g)
         h5.create_dataset('t', data=-edist.t)
         h5.create_dataset('x', data=edist.x)
         h5.create_dataset('y', data=edist.y)
         h5.create_dataset('xp', data=edist.xp)
         h5.create_dataset('yp', data=edist.yp)
-        h5.create_dataset('charge', data = edist.charge())
-        # h5.close()
+        # h5.create_dataset('charge', data=[edist.charge()])
+        # h5.create_dataset('part_charge', data=[edist.part_charge])
+    _logger.debug(ind_str + 'done')
 
-def read_edist_hdf5(filepath, charge=None):
 
+def read_edist_hdf5(filepath, charge=None):
+    _logger.info('reading electron distribution from {}'.format(filepath))
     edist = GenesisElectronDist()
     with h5py.File(filepath, 'r') as h5:
 
-        edist.g =  h5.get('p')[:]
-        edist.t =  -h5.get('t')[:]
-        edist.x =  h5.get('x')[:]
-        edist.y =  h5.get('y')[:]
-        edist.xp =  h5.get('xp')[:]
-        edist.yp =  h5.get('yp')[:]
+        edist.g = h5.get('p')[:]
+        edist.t = -h5.get('t')[:]
+        edist.x = h5.get('x')[:]
+        edist.y = h5.get('y')[:]
+        edist.xp = h5.get('xp')[:]
+        edist.yp = h5.get('yp')[:]
+        npart = len(edist.g)
+        
+        try:
+            edist.part_charge = h5.get('part_charge')
+            _logger.debug('retrieved edist charge per particle = {}'.format(edist.part_charge))
+        except TyprError:
+            edist.part_charge = None
+            _logger.warn('no part_charge in edist')
+        
+        if charge != None:
+            edist.part_charge = charge / npart
+            _logger.debug('particle charge is overriden to {}'.format(edist.part_charge))
+        else:
+            if edist.part_charge == None:
+                _logger.warn('particle charge was not provided neither in the file nor as an argument')
+        
+    return edist
 
-        if charge is not None:
-            charge = h5.get('charge')[:]
 
-    edist.part_charge = charge / edist.g.size
-    return edist
+def write_beamtwiss_hdf5(beam, filepath):
+    _logger.info('writing electron beam (twiss) to {}'.format(filepath))
+    with h5py.File(filepath, 'w') as h5:
+        h5.create_dataset('s', data=beam.s)
+        h5.create_dataset('gamma', data=beam.g)
+        h5.create_dataset('delgam', data=beam.dg)
+        h5.create_dataset('current', data=beam.I)
+        h5.create_dataset('ex', data=beam.emit_xn)
+        h5.create_dataset('ey', data=beam.emit_yn)
+        h5.create_dataset('betax', data=beam.beta_x)
+        h5.create_dataset('betay', data=beam.beta_y)
+        h5.create_dataset('alphax', data=beam.alpha_x)
+        h5.create_dataset('alphay', data=beam.alpha_y)
+        h5.create_dataset('xcenter', data=beam.x)
+        h5.create_dataset('ycenter', data=beam.y)
+        h5.create_dataset('pxcenter', data=beam.px)
+        h5.create_dataset('pycenter', data=beam.py)
+        if hasattr(beam, 'bunch'):
+            h5.create_dataset('bunch', data=beam.bunch)
+        else:
+            h5.create_dataset('bunch', data=np.zeros_like(beam.s))
+        if hasattr(beam, 'bunchphase'):
+            h5.create_dataset('bunchphase', data=beam.bunchphase)
+        else:
+            h5.create_dataset('bunchphase', data=np.zeros_like(beam.s))
+        if hasattr(beam, 'emod'):
+            h5.create_dataset('emod', data=beam.emod)
+        else:
+            h5.create_dataset('emod', data=np.zeros_like(beam.s))
+        if hasattr(beam, 'emodphase'):
+            h5.create_dataset('emodphase', data=beam.emodphase)
+        else:
+            h5.create_dataset('emodphase', data=np.zeros_like(beam.s))
+    _logger.debug(ind_str + 'done')
+
+
+def read_beamtwiss_hdf5(filepath):
+    _logger.info('reading electron beam (twiss) from {}'.format(filepath))
+    beam = BeamArray()
+    with h5py.File(filepath, 'r') as h5:
+        beam.s = h5.get('s')[:]
+        beam.g = h5.get('gamma')[:]
+        beam.dg = h5.get('delgam')[:]
+        beam.I = h5.get('current')[:]
+        beam.emit_xn = h5.get('ex')[:]
+        beam.emit_yn = h5.get('ey')[:]
+        beam.beta_x = h5.get('betax')[:]
+        beam.beta_y = h5.get('betay')[:]
+        beam.alpha_x = h5.get('alphax')[:]
+        beam.alpha_y = h5.get('alphay')[:]
+        beam.x = h5.get('xcenter')[:]
+        beam.y = h5.get('ycenter')[:]
+        beam.px = h5.get('pxcenter')[:]
+        beam.py = h5.get('pycenter')[:]
+    _logger.debug(ind_str + 'done')
+    return beam
diff --git a/ocelot/common/math_op.py b/ocelot/common/math_op.py
index 6739534c..81e658d4 100644
--- a/ocelot/common/math_op.py
+++ b/ocelot/common/math_op.py
@@ -627,3 +627,32 @@ def gauss(x, p):  # p[0]==mean, p[1]==stdev p[2]==peak
     Y1 = gauss(X, p1)
     RMS = fit_stdev
     return (Y1, RMS)
+
+
+def mprefix(value, order_bias=0.05, apply=1):
+    '''
+    estimate metric prefix for a scalar or np.array
+    accepts floating point number
+    order_bias is an ammount of order of magnitudes to round up to. Allows to avoid values like 995 instead of 0.995k. 1/3 corresponds to ...980,990,0.10,0.11...
+    returns scaled values (float or numpy arrayof floats), its prefix (string), and applied order of magnitude (should it need to be reused)
+        '''
+    prefix_range = (-30, 30)
+    prefixes = {-30:'q', -27:'r', -24:'y', -21:'z', -18:'a', -15:'f', -12:'p', -9:'n', -6:r'$\mu$', -3:'m', 0:'', 3:'k', 6:'M', 9:"G", 12:'T', 15:'P', 18:'E', 21:'Z', 24:'Y', 27:'R', 30:'Q'}
+        
+    if not apply:
+        return (value, '', 0)
+    
+    else:
+        if not np.isscalar(value):
+            order = np.floor(np.log10(np.nanmax(value)) / 3 + order_bias) * 3
+        else:
+            order = np.floor(np.log10(value) / 3 + order_bias) * 3
+        if order < prefix_range[0]:
+            order = prefix_range[0]
+        if order > prefix_range[1]:
+            order = prefix_range[1]
+        scaling = 10**order
+        value_out = value / scaling
+        prefix_out = prefixes.get(order)
+        
+        return(value_out, prefix_out, order)
\ No newline at end of file
diff --git a/ocelot/common/py_func.py b/ocelot/common/py_func.py
index c574b5ba..3e3cb6ba 100644
--- a/ocelot/common/py_func.py
+++ b/ocelot/common/py_func.py
@@ -40,7 +40,7 @@ def background(command):
 def copy_this_script(file, folderPath):
     scriptName = os.path.basename(file)
     scriptPath = os.path.realpath(file)
-    cmd = 'cp ' + scriptPath + ' ' + folderPath + 'exec_' + scriptName + ' '
+    cmd = 'cp ' + scriptPath + ' ' + os.path.join(folderPath, 'exec_' + scriptName) + ' '
     os.system(cmd)
 
 def filename_from_path(path_string):
diff --git a/ocelot/cpbd/beam.py b/ocelot/cpbd/beam.py
index bbbe20ad..517d4e3d 100644
--- a/ocelot/cpbd/beam.py
+++ b/ocelot/cpbd/beam.py
@@ -467,11 +467,14 @@ def sort(self):
             _logger.log(5, ind_str + 'size {:}'.format(values.size))
             setattr(self, attr, values[inds])
 
-    def equidist(self):
-        dsarr = (self.s - np.roll(self.s, 1))[1:]
+    def equidist(self, ds=None):
+        dsarr = (self.s - np.roll(self.s,1))[1:]
         dsm = np.mean(dsarr)
-        if (np.abs(dsarr - dsm) / dsm > 1 / 1000).any():
-            s_new = np.linspace(np.amin(self.s), np.amax(self.s), self.len())
+        if (np.abs(dsarr-dsm)/dsm > 1/1000).any():
+            if ds is None:
+                s_new = np.linspace(np.amin(self.s), np.amax(self.s), self.len())
+            else:
+                s_new = np.arange(np.amin(self.s), np.amax(self.s), ds)
             for attr in self.params():
                 if attr == 's':
                     continue
@@ -612,7 +615,7 @@ def add_chirp_poly(self, coeff, s0=None):
         if s0 is None:
             s0 = (np.amax(self.s) - np.amin(self.s)) / 2
         elif isinstance(s0, str) is not True:
-            s0 = s0 / 1e6
+            s0 = s0# / 1e6
         else:
             raise ValueError("s0 must be None or some value")
 
@@ -634,6 +637,78 @@ def to_array(self, *args, **kwargs):
         raise NotImplementedError('Method inherited from Beam() class, not applicable for BeamArray objects')
 
 
+class BeamFormFactor:
+    '''
+    contains and calculates electron beam form-factor (fourier transform of currenta profile)
+    from the electron beam "BeamArray" object
+    '''
+    def __init__(self, beam_array=None):
+        self.cfactor = None #modulus of form-factor
+        self.frequency = None #frequency in Hz
+        self.beam_array = beam_array #original beam file
+        
+        if self.beam_array is not None:
+            self.beam_array.sort()
+            self.beam_array.equidist()
+            self.calc()
+
+    def __len__(self):
+        return np.size(self.cfactor)
+
+    # def current_profile(self):
+    #     return self.beam_array.s, self.beam_array.I
+
+    def calc(self):
+        '''
+        calculates the form-factor and populates self.modulus and self.frequency
+        '''
+        I_norm = self.beam_array.I / self.beam_array.charge()
+        self.cfactor = np.fft.fft(I_norm)
+        ds = np.abs(self.beam_array.s[1] - self.beam_array.s[0])
+        self.frequency = np.fft.fftfreq(len(self), ds / speed_of_light)
+        idx = len(self) // 2
+        
+        self.cfactor = self.cfactor[:idx]
+        self.frequency = self.frequency[:idx]
+
+
+class Trajectory:
+    def __init__(self):
+        self.ct = []
+        self.E = []
+        self.x = []
+        self.y = []
+        self.xp = []
+        self.yp = []
+        self.z = []
+        self.s = []
+
+    def add(self, ct, x, y, xp, yp, z, s):
+        self.ct.append(ct)
+        self.x.append(x)
+        self.y.append(y)
+        self.xp.append(xp)
+        self.yp.append(yp)
+        self.z.append(z)
+        self.s.append(s)
+
+    def last(self):
+        p = Particle()
+
+        p.ct = self.ct[len(self.ct) - 1]
+        p.x = self.x[len(self.x) - 1]
+        p.y = self.y[len(self.y) - 1]
+        p.xp = self.xp[len(self.xp) - 1]
+        p.yp = self.yp[len(self.yp) - 1]
+        try:
+            p.E = self.E[len(self.E) - 1]
+        except IndexError:
+            return 0
+        p.s = self.s[len(self.s) - 1]
+
+        return p
+
+
 class ParticleArray:
     """
     array of particles of fixed size; for optimized performance
@@ -2146,9 +2221,9 @@ def generate_beam(E, I=5000, l_beam=3e-6, **kwargs):
                     l_beam * 6 if gaussian,
     nslice - number of slices in the beam
     """
-
+    
     _logger.info('generating electron beam distribution')
-
+    
     beam = Beam()
     beam.E = E
     beam.tlen = l_beam / speed_of_light * 1e15
@@ -2171,7 +2246,7 @@ def generate_beam(E, I=5000, l_beam=3e-6, **kwargs):
             nslice = value
         if key == 'dE':
             beam.dg = value / m_e_GeV
-
+    
     if 'l_window' not in kwargs:
         if beam.shape is ['gaussian', 'gauss', 'g']:
             l_window = l_beam * 6
@@ -2181,12 +2256,12 @@ def generate_beam(E, I=5000, l_beam=3e-6, **kwargs):
             raise ValueError('Beam() shape can be either "gaussian" or "flattop"')
     else:
         l_window = kwargs['l_window']
-
+    
     beam_arr = beam.to_array(nslice, l_window)
-
+    
     if 'chirp' in kwargs:
         beam_arr.add_chirp(kwargs['chirp'])
-
+    
     return beam_arr
 
 
diff --git a/ocelot/gui/beam_plot.py b/ocelot/gui/beam_plot.py
index ffa2b18b..43ea9a9f 100644
--- a/ocelot/gui/beam_plot.py
+++ b/ocelot/gui/beam_plot.py
@@ -9,6 +9,7 @@
 import numpy as np
 import logging
 
+
 from ocelot.adaptors.genesis import *
 from ocelot.common.globals import *  # import of constants like "h_eV_s" and
 from ocelot.common.math_op import *  # import of mathematical functions
@@ -16,6 +17,7 @@
 from ocelot.optics.utils import calc_ph_sp_dens
 from ocelot.optics.wave import *
 from ocelot.gui.settings_plot import *
+from ocelot.cpbd.beam import BeamFormFactor
 
 _logger = logging.getLogger(__name__)
 
@@ -50,6 +52,10 @@ def plot_beam(beam, figsize=3, showfig=True, savefig=False, fig=None, plot_xy=No
 
     if fig == None:
         fig = plt.figure()
+    elif type(fig) is str:
+        fig = plt.figure(fig)
+    else:
+        pass
     fig.clf()
 
     idx = beam.idx_max()
@@ -83,11 +89,11 @@ def plot_beam(beam, figsize=3, showfig=True, savefig=False, fig=None, plot_xy=No
     plt.grid(True)
     ax.set_xlabel(r'$s [\mu m]$', fontsize=fontsize)
     # p1,= plt.plot(1.e6 * np.array(beam.s),1.e-3 * np.array(beam.eloss),'r',lw=3)
-    p1, = plt.plot(1.e6 * np.array(beam.s), g_dev, 'r', lw=3)
-    plt.plot(1.e6 * beam.s[idx], g_dev[idx], 'bs')
-    ax = ax.twinx()
     p2, = plt.plot(1.e6 * np.array(beam.s), beam.dg, 'g', lw=3)
     plt.plot(1.e6 * beam.s[idx], beam.dg[idx], 'bs')
+    ax = ax.twinx()
+    p1, = plt.plot(1.e6 * np.array(beam.s), g_dev, 'r', lw=3)
+    plt.plot(1.e6 * beam.s[idx], g_dev[idx], 'bs')
     ax.legend([p1, p2], [r'$\gamma$ + ' + str(g0), r'$\delta \gamma$'], loc='best')
 
     ax = fig.add_subplot(2 + plot_xy, 2, 3, sharex=ax)
@@ -169,6 +175,88 @@ def plot_beam(beam, figsize=3, showfig=True, savefig=False, fig=None, plot_xy=No
 
     _logger.debug(ind_str + 'done')
 
+
+def plot_beam_form_factor(form_factor: BeamFormFactor, x_axis_units='THz', x_axis_limits=(None, None), y_axis_limits=(None, None),
+                          figsize=(2 * 3, 3 * 3), normalize=True, fig_name='Beam Form Factor', log_scale=False, showtext=True,
+                          savefig=False, showfig=True, **kwargs):
+    '''
+    plots a BeamFormFactor object
+    '''
+    if not showfig and not savefig:
+        return
+
+    start_time = time.time()
+    _logger.info('plotting Beam Form Factor')
+    fig = plt.figure(fig_name)
+    fig.clf()
+    fig.set_size_inches(figsize, forward=True)
+
+    ax_current_profile = fig.add_subplot(2, 1, 1)
+    s, current = form_factor.beam_array.s, form_factor.beam_array.I
+    ax_current_profile.plot(s * 1e6, current * 1e-3, **kwargs)
+    ax_current_profile.set_title('Current profile', fontsize=15)
+    ax_current_profile.set_xlabel('s [$\mu$m]')
+    ax_current_profile.set_ylabel('peak current [kA]')
+    if showtext:
+        ax_current_profile.text(0.97, 0.97, 'Q={:.2f}pC'.format(form_factor.beam_array.charge()*1e12), 
+                                horizontalalignment='right', verticalalignment='top', transform=ax_current_profile.transAxes, fontsize=12, color='black')
+
+    form_factor.calc()
+    frequency, ffactor =  form_factor.frequency, np.abs(form_factor.cfactor)
+    if normalize:
+        ffactor /= ffactor[0]
+        
+    xlable = '$\omega$ [Hz]'
+    if x_axis_units in ['MHz', 'mhz']:
+        frequency = frequency * 1e-6
+        xlable = '$\omega$ [MHz]'
+    elif x_axis_units in ['GHz', 'ghz']:
+        frequency = frequency * 1e-9
+        xlable = '$\omega$ [GHz]'
+    elif x_axis_units in ['THz', 'thz', 'f']:
+        frequency = frequency * 1e-12
+        xlable = '$\omega$ [THz]'
+    elif x_axis_units in ['keV', 'kev']:
+        frequency = frequency * 2 * np.pi * hr_eV_s * 1e-3
+        xlable = '$\epsilon$ [keV]'
+    elif x_axis_units in ['eV', 'ev']:
+        frequency = frequency * 2 * np.pi * hr_eV_s
+        xlable = '$\epsilon$ [eV]'
+    elif x_axis_units in ['meV', 'mev']:
+        frequency = frequency * 2 * np.pi * hr_eV_s * 1e3
+        xlable = '$\epsilon$ [meV]'
+    else:
+        _logger.warning(ind_str + 'x_axis_units must one of \'MHz\', \'GHz\', \'THz\', \'keV\', \'eV\', \'meV\'')
+
+    ax_form_factor = fig.add_subplot(2, 1, 2)
+    if log_scale:
+        ax_form_factor.semilogy(frequency, ffactor**2, **kwargs)
+    else:
+        ax_form_factor.plot(frequency, ffactor**2, **kwargs)
+    ax_form_factor.set_title('Form factor profile', fontsize=15)
+    ax_form_factor.set_ylabel('|form factor|^2 [a. u.]')
+    ax_form_factor.set_xlabel(xlable)
+    ax_form_factor.set_xlim(*x_axis_limits)
+    ax_form_factor.set_ylim(*y_axis_limits)
+    
+    fig.subplots_adjust(wspace=0.4, hspace=0.4)
+
+    plt.draw()
+    _logger.debug(ind_str + 'done in {:.2f} seconds'.format(time.time() - start_time))
+    if savefig:
+        _logger.debug(ind_str + 'saving figure ' + fig_name)
+        if not isinstance(savefig, str):
+            fig.savefig(fig_name + '.png')
+        else:
+            fig.savefig(fig_name + '.' + savefig)
+
+    if showfig:
+        _logger.debug('showing figure ' + fig_name)
+        plt.show()
+    else:
+        plt.close('all')
+
+
 @if_plottable
 @save_show
 def plot_estimator_power_z(fel, z=None, fig=None, und_duty_factor=1, fs=False):
@@ -198,7 +286,7 @@ def plot_estimator_power_z(fel, z=None, fig=None, und_duty_factor=1, fs=False):
     return fig
     
     #fig.savefig(exp_dir + 'power_sat.png', format = 'png')
-    # fig.show()
+    return fig
 
 @if_plottable
 @save_show
@@ -233,7 +321,6 @@ def plot_estimator_spectrogram(fel, z=None, fig=None, cmap='Reds', **kwargs):
     ax.set_ylabel('E [eV]')
     ax.autoscale(tight=1)
     return fig
-    # fig.show()
 
 @if_plottable
 @save_show
@@ -251,7 +338,7 @@ def plot_estimator_spectrum(fel, z=None, fig=None, **kwargs):
     ax.set_ylabel('spec. density')
     ax.autoscale(tight=1)
     return fig
-    # fig.show()
+
 
 @if_plottable
 @save_show
@@ -265,7 +352,7 @@ def plot_estimator_power_evo(fel, fig=None, und_duty_factor=1, **kwargs):
     
     P=[]
     E=[]
-    z = np.linspace(0,fel.z_sat_min,20)
+    z = np.linspace(0,fel.z_sat_min,50)
     for zi in z:
         P.append(np.amax(fel.P(zi)))
         E.append(fel.E(zi))
@@ -275,7 +362,7 @@ def plot_estimator_power_evo(fel, fig=None, und_duty_factor=1, **kwargs):
     ax.set_ylabel('P [W]')
     ax.set_xlabel('z [m]')
     return fig
-    # fig.show()
+
 
 @if_plottable
 @save_show
@@ -288,7 +375,7 @@ def plot_estimator_energy_evo(fel, fig=None, und_duty_factor=1, **kwargs):
     ax = fig.gca()
     
     E=[]
-    z = np.linspace(0,fel.z_sat_min,20)
+    z = np.linspace(0,fel.z_sat_min,50)
     for zi in z:
         E.append(fel.E(zi))
         
@@ -297,6 +384,5 @@ def plot_estimator_energy_evo(fel, fig=None, und_duty_factor=1, **kwargs):
     ax.set_ylabel('E [J]')
     ax.set_xlabel('z [m]')
     return fig
-    # fig.show()
     
     
\ No newline at end of file
diff --git a/ocelot/gui/dfl_plot.py b/ocelot/gui/dfl_plot.py
index 227c6e14..4912f2f8 100644
--- a/ocelot/gui/dfl_plot.py
+++ b/ocelot/gui/dfl_plot.py
@@ -18,7 +18,7 @@
 from ocelot.common.globals import *  # import of constants like "h_eV_s" and
 from ocelot.common.math_op import *  # import of mathematical functions like gauss_fit
 from ocelot.utils.xfel_utils import *
-from ocelot.optics.utils import calc_ph_sp_dens
+#from ocelot.optics.utils import calc_ph_sp_dens
 from ocelot.optics.wave import *
 
 from ocelot.gui.colormaps2d.colormap2d import *
@@ -48,7 +48,7 @@ def plot_dfl_all(dfl, **kwargs):
 @if_plottable
 def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, legend=True, phase=False, fig_name=None,
              auto_zoom=False, column_3d=True, savefig=False, showfig=True, return_proj=False, line_off_xy=True,
-             slice_xy=False, log_scale=0, cmap_cutoff=0, vartype_dfl=None, **kwargs):
+             slice_xy=False, log_scale=0, cmap_cutoff=0, vartype_dfl=None, plot_sp_dens=True, **kwargs):
     """
     Plots dfl radiation object in 3d using matplotlib.
 
@@ -71,6 +71,7 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
     :param log_scale: bool type variable, if True, log scale will be used for potting
     :param cmap_cutoff: 0 <= cmap_cutoff <= 1; all pixels that have intensity lower than cmap_cutoff will be seted to white color
     :param vartype_dfl: the data type to store dfl in memory [either complex128 (two 64-bit floats) or complex64 (two 32-bit floats)], may save memory
+    :param plot_sp_dens: whether to recalculate spectral density in units of mJ/eV
     :param kwargs: 
     :return:
     """
@@ -103,6 +104,8 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
         domains = dfl_copy.domains()
     else:
         dfldomain_check(domains)
+    
+    _logger.info(ind_str + "domains={}".format(str(domains)))
 
     if 'k' in domains:
         far_field = True
@@ -129,14 +132,21 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
         phase = True
         freq_domain = False
         z_lim = []
+        ncar_z = 1
+        leng_z = 1
     xlamds = dfl_copy.xlamds
-
+    
     # number of mesh points
     ncar_x = dfl_copy.Nx()
     leng_x = dfl_copy.Lx()  # transverse size of mesh [m]
     ncar_y = dfl_copy.Ny()
     leng_y = dfl_copy.Ly()
     E_pulse = dfl_copy.E()
+    
+    _logger.debug(ind_str + "xlamds = {:.2e}".format(xlamds))
+    _logger.debug(ind_str + "Nx = {}, Ny = {}, Nz = {}".format(ncar_x, ncar_y, ncar_z))
+    _logger.debug(ind_str + "Lx = {:.2e}, Ly = {:.2e}, Lz = {:.2e}".format(leng_x, leng_y, leng_z))
+    _logger.debug(ind_str + "E_pulse = {:.2e} J".format(E_pulse))
 
     if dfl_copy.Nz() != 1:
         if freq_domain:
@@ -241,8 +251,20 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
         yz_title = 'Side projection'
         z_proj = dfl_copy.int_z()
 
-    dx = abs(x[1] - x[0])
-    dy = abs(y[1] - y[0])
+    dx, dy, dz = 0, 0, 0
+    if ncar_x > 1:
+        dx = abs(x[1] - x[0])
+    if ncar_y > 1:
+        dy = abs(y[1] - y[0])
+    if ncar_z > 1:
+        dz = abs(z[1] - z[0]) #TODO: would not work in case of non-uniform steps
+    
+    
+    if freq_domain:
+        if plot_sp_dens:
+            z_proj = calc_ph_sp_dens(z_proj, z, E_pulse*1e0, spec_squared=1)
+            z_labelv = r'[J/eV]'
+            ######################################################
 
     if log_scale:
         suffix += '_log'
@@ -302,7 +324,7 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
 
     if phase == True:
         ax_ph = fig.add_subplot(2, 2 + column_3d, 4 + column_3d, sharex=ax_int, sharey=ax_int)
-        ax_ph.pcolormesh(x, y, xy_proj_ph, cmap=cmap_ph)
+        ax_ph.pcolormesh(x, y, xy_proj_ph, cmap=cmap_ph, vmin=-np.pi, vmax=np.pi)
         ax_ph.axis([np.min(x), np.max(x), np.min(y), np.max(y)])
         ax_ph.set_title('Phase', fontsize=15)
     else:
@@ -315,19 +337,27 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
         ax_z.set_xlabel(z_label)
         ax_z.set_ylabel(z_labelv)
         ax_z.set_ylim(ymin=0)
-
+        ff = fwhm3(np.array(z_proj), height=0.5, peakpos=-1, total=1)
+        pzc, pzw = ff[0], ff[1]
+        center_z = z[0] + dz*pzc #central position
+        fwhm_z = dz * pzw
+        #ax_z.text(0.05, 0.95, r"$(\Delta E/E)_{fwhm}$= %.2e" % (zw/zc), fontsize=12, horizontalalignment='left', verticalalignment='top', transform=ax_z.transAxes, color='red')
+        ax_z.text(0.05, 0.95, 'fwhm={:.3g} '.format(fwhm_z) + r' [{:}]'.format(unit_z), fontsize=12, horizontalalignment='left', verticalalignment='top', transform=ax_z.transAxes, color='black')
+        
     ax_proj_x = fig.add_subplot(2, 2 + column_3d, 3 + column_3d, sharex=ax_int)
     ax_proj_x.set_title(x_title, fontsize=15)
 
     if sum(x_line) != 0:
         try:
             x_line_f, rms_x = gauss_fit(x, x_line)  # fit with Gaussian, and return fitted function and rms
-        except RuntimeWarning:
+        except (TypeError, RuntimeWarning) as error:
+            _logger.warning(ind_str + str(error))
             x_line_f = np.zeros_like(x_line)
             rms_x = 0
         try:
             fwhm_x = fwhm3(x_line)[1] * dx  # measure FWHM
-        except ValueError:
+        except (TypeError, IndexError, ValueError) as error:
+            _logger.warning(ind_str + str(error))
             fwhm_x = 0
     else:
         x_line_f = np.zeros_like(x_line)
@@ -360,12 +390,14 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
     if sum(y_line) != 0:
         try:
             y_line_f, rms_y = gauss_fit(y, y_line)  # fit with Gaussian, and return fitted function and rms
-        except RuntimeWarning:
+        except (TypeError, RuntimeWarning) as error:
+            _logger.warning(ind_str + str(error))
             y_line_f = np.zeros_like(y_line)
             rms_y = 0
         try:
             fwhm_y = fwhm3(y_line)[1] * dy  # measure FWHM
-        except ValueError:
+        except (TypeError, IndexError, ValueError) as error:
+            _logger.warning(ind_str + str(error))
             fwhm_y = 0
     else:
         y_line_f = np.zeros_like(y_line)
@@ -514,9 +546,180 @@ def plot_dfl(dfl, domains=None, z_lim=[], xy_lim=[], figsize=4, cmap=def_cmap, l
     else:
         return
 
+@if_plottable
+def plot_two_dfls(dfl_first, dfl_second, domains='s', label_first=None, label_second=None, title=None,
+            x_lim=None, y_lim=None, slice_xy=False, phase=False, savefig=False, showfig=True, filePath=None, fig_name=None):
+    """ 
+    Parameters
+    ----------
+    dfl_first : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+    dfl_second : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+    domains : str, optional
+        A transverse domain in which the fields will be represented. The default is 's'.
+    label_first : str, optional
+        Label of the first field to be plotted in the legend. When the default is None no label will be displayed.
+    label_second : str, optional
+        Label of the second field to be plotted in the legend. When the default is None no label will be displayed.
+    x_lim : float, optional
+        Limit of the x scale whether in um or urad. When the default is None minimum scale of two field will be plotted.
+    y_lim : float, optional
+        Limit of the y scale whether in um or urad. When the default is None minimum scale of two field will be plotted.
+    slice_xy : bool type, optional
+        if True, slices will be plotted; if False, projections will be plotted.
+    phase : bool type, optional
+        can replace XY projection with the phasefront distribution. The default is False.
+    figname : str, optional
+        The name of the figure to be plotted and saved. The default is 'figname'.
+
+    Returns
+    -------
+    None.
+
+    """
+    
+    _logger.info('Plotting two dfls in process...')
+    start_time = time.time()
+
+    cmap_ph = plt.get_cmap('hsv')
+    
+    dfl1 = deepcopy(dfl_first)
+    dfl2 = deepcopy(dfl_second)
+    
+    if filePath is None:
+        filePath = dfl1.filePath
+    
+    if fig_name is None:
+        if dfl1.fileName() == '':
+            fig = plt.figure('Radiation comparison' + domains)
+        else:
+            fig = plt.figure('Radiation comparison ' + domains + ' ' + dfl1.fileName() + ' ' + dfl2.fileName())
+    else:
+        fig = plt.figure(fig_name + domains)
+    
+    figsize = 6
+    # fig = plt.figure(fig_name)
+    plt.clf()
+     
+    fig.set_size_inches(4*figsize, figsize, forward=True)
+    if title is not None: 
+        fig.suptitle(title, fontsize=18, ha='right')
+        
+    ax_x = fig.add_subplot(1, 4, 1)
+    ax_y = fig.add_subplot(1, 4, 2)
+    ax_x2 = ax_x.twinx()  # instantiate a second axes that shares the same x-axis
+    ax_y2 = ax_y.twinx()
+
+    _logger.info(ind_str + "domains={}".format(str(domains)))
+
+    if domains == 'k':
+        label_x = r'$\theta_y, \mu rad$'
+        label_y = r'$\theta_x, \mu rad$'
+    elif domains == 's':
+        label_x = r'$x, \mu m$'
+        label_y = r'$y, \mu m$'
+    dfl1.to_domain(domains)
+    dfl2.to_domain(domains)
+    
+    if None in [x_lim, y_lim]:
+        x_lim = min(np.max(dfl1.scale_x())*1e6, np.max(dfl2.scale_x())*1e6)
+        y_lim = min(np.max(dfl1.scale_y())*1e6, np.max(dfl2.scale_y())*1e6)
+
+    _logger.debug(ind_str + "x_lim = {}, y_lim = {}".format(x_lim, y_lim))
+    ax_y.set_xlim(-y_lim, y_lim)
+    ax_y2.set_xlim(-y_lim, y_lim)
+    ax_x.set_xlim(-x_lim, x_lim)
+    ax_x2.set_xlim(-x_lim, x_lim)        
+    
+    ax_y.grid()
+    ax_x.grid()
+    
+    if slice_xy is True:   
+        fig.text(0.01, 0.01, 'x- y- slice', fontsize=18)
+        I_1x = np.sum(dfl1.intensity(), axis=0)[dfl1.Ny()//2+1, :]
+        I_2x = np.sum(dfl2.intensity(), axis=0)[dfl2.Ny()//2+1, :]
+        I_1y = np.sum(dfl1.intensity(), axis=0)[:, dfl1.Nx()//2+1]
+        I_2y = np.sum(dfl2.intensity(), axis=0)[:, dfl2.Nx()//2+1]
+    elif slice_xy is False:
+        fig.text(0.01, 0.01, 'x- y- integrated', fontsize=18)
+        I_1x = np.sum(dfl1.intensity(), axis=(0,1))
+        I_2x = np.sum(dfl2.intensity(), axis=(0,1))
+        I_1y = np.sum(dfl1.intensity(), axis=(0,2))
+        I_2y = np.sum(dfl2.intensity(), axis=(0,2))
+    else: 
+        raise AttributeError('slice_xy is a boolean type')
+        _logger.error(ind_str + 'slice_xy is a boolean type')
+       
+    ax_x.plot(dfl1.scale_x()*1e6, I_1x, c='b', label=label_first)
+    ax_x2.plot(dfl2.scale_x()*1e6, I_2x, c='green', label=label_second)
+    
+    ax_y.plot(dfl1.scale_y()*1e6, I_1y, c='b', label=label_first)
+    ax_y2.plot(dfl2.scale_y()*1e6, I_2y, c='green', label=label_second)    
+    
+    if None not in [label_first, label_second]:
+        ax_y2.legend(fontsize=12, bbox_to_anchor=(0, 0.92), loc='upper left')#, loc=1)
+        ax_y.legend(fontsize=12, bbox_to_anchor=(0, 0.995), loc='upper left')#, loc=2)
+        ax_x2.legend(fontsize=12, bbox_to_anchor=(0, 0.92), loc='upper left')#, loc=1)
+        ax_x.legend(fontsize=12, bbox_to_anchor=(0, 0.995), loc='upper left')#, loc=2)
+        
+    ax_xy1 = fig.add_subplot(1, 4, 3)
+    ax_xy2 = fig.add_subplot(1, 4, 4)
+
+    if phase == True:
+        xy_proj_ph1 = np.angle(np.sum(dfl1.fld, axis=0))
+        xy_proj_ph2 = np.angle(np.sum(dfl2.fld, axis=0))
+        ax_xy1.pcolormesh(dfl1.scale_x()*1e6, dfl1.scale_y()*1e6, xy_proj_ph1, cmap=cmap_ph, vmin=-np.pi, vmax=np.pi)        
+        ax_xy2.pcolormesh(dfl2.scale_x()*1e6, dfl2.scale_y()*1e6, xy_proj_ph2, cmap=cmap_ph, vmin=-np.pi, vmax=np.pi)
+    else:
+        ax_xy1.pcolormesh(dfl1.scale_x()*1e6, dfl1.scale_y()*1e6, np.sum(dfl1.intensity(), axis=0))         
+        ax_xy2.pcolormesh(dfl2.scale_x()*1e6, dfl2.scale_y()*1e6, np.sum(dfl2.intensity(), axis=0))
+
+    ax_xy2.set_xlim(-x_lim, x_lim)
+    ax_xy2.set_ylim(-y_lim, y_lim)
+    ax_xy1.set_xlim(-x_lim, x_lim)
+    ax_xy1.set_ylim(-y_lim, y_lim)
+
+    ax_xy1.set_title(label_first, fontsize=14, color='b')      
+    ax_xy2.set_title(label_second, fontsize=14, color='green')
+          
+    ax_xy1.set_ylabel(label_y, fontsize=16)
+    ax_xy1.set_xlabel(label_x, fontsize=16)
+    ax_xy2.set_ylabel(label_y, fontsize=16)
+    ax_xy2.set_xlabel(label_x, fontsize=16)
+    ax_x.set_xlabel(label_x, fontsize=16)
+    ax_y.set_xlabel(label_y, fontsize=16)
+    ax_x.set_ylabel('arb.units', fontsize=16)
+    ax_y.set_ylabel('arb.units', fontsize=16)
+    ax_x.set_ylim(0)
+    ax_y.set_ylim(0)
+    ax_x2.set_ylim(0)
+    ax_y2.set_ylim(0)
+    plt.tight_layout()
+    
+    if savefig != False:
+        if savefig == True:
+            savefig = 'png'
+        _logger.debug(ind_str + 'saving *{:}.{:}'.format(fig_name, savefig))
+        fig.savefig(filePath + fig_name + '.' + str(savefig), format=savefig)
+    _logger.debug(ind_str + 'done in {:.2f} seconds'.format(time.time() - start_time))
+
+    plt.draw()
+
+    if showfig == True:
+        _logger.debug(ind_str + 'showing two dfls')
+        rcParams["savefig.directory"] = os.path.dirname(filePath)
+        plt.show()
+    else:
+        plt.close(fig)   
+    _logger.info(ind_str + 'plotting two dfls done in {:.2f} seconds'.format(time.time() - start_time))
+
+def plot_wigner(*args,**kwargs):
+    _logger.warning('plotting wigner for time-frequency domain migrated to plot_wigner_z')
+    return plot_wigner_z(*args,**kwargs)
 
 @if_plottable
-def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, None), y_lim=(None, None), downsample=1,
+def plot_wigner_z(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, None), y_lim=(None, None), v_lim=(None, None), downsample=1,
                 autoscale=None, figsize=3, cmap='seismic', fig_name=None, savefig=False, showfig=True,
                 plot_proj=1, plot_text=1, plot_moments=0, plot_cbar=0, log_scale=0, **kwargs):
     """
@@ -572,35 +775,56 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
     plt.clf()
     fig.set_size_inches((4.5 * figsize, 3.25 * figsize), forward=True)
 
-    power = W.power()
-    spec = W.spectrum()
+    power = W.proj_s()
+    spec = W.proj_k()
     wigner = W.wig
     wigner_lim = np.amax(abs(W.wig))
+    
+    if v_lim[0] is None:
+        v_min = -wigner_lim
+    else:
+        v_min = v_lim[0]
+    
+    if v_lim[1] is None:
+        v_max = wigner_lim
+    else:
+        v_max = v_lim[1]
+        
+    v_maxabs = np.amax([np.abs(v_min), np.abs(v_max)])
+    
     if plot_moments:
         inst_freq = W.inst_freq()
         group_delay = W.group_delay()
-
-    if x_units == 'fs':
-        power_scale = -W.s / speed_of_light * 1e15
-        p_label_txt = 't [fs]'
-        if plot_moments:
-            group_delay = group_delay / speed_of_light * 1e15
-    else:
-        power_scale = W.s * 1e6
-        p_label_txt = 's [$\mu$m]'
-        if plot_moments:
-            group_delay = group_delay * 1e6
-
-    if y_units in ['ev', 'eV']:
-        spec_scale = W.phen
-        f_label_txt = '$E_{photon}$ [eV]'
-        if plot_moments:
-            inst_freq = inst_freq
-    else:
-        spec_scale = W.freq_lamd
-        f_label_txt = '$\lambda$ [nm]'
-        if plot_moments:
-            inst_freq = h_eV_s * speed_of_light * 1e9 / inst_freq
+    
+    # if W.domain in ['x','y','s']:
+    if isinstance(W, WignerDistributionTransverse):
+        power_scale = W.s
+        p_label_txt = 's [m]'
+        spec_scale = W.theta()
+        f_label_txt = '$\{theta}$ [rad]'
+    
+    elif isinstance(W, WignerDistributionLongitudinal):
+        if x_units == 'fs':
+            power_scale = -W.s / speed_of_light * 1e15
+            p_label_txt = 't [fs]'
+            if plot_moments:
+                group_delay = -group_delay / speed_of_light * 1e15
+        else:
+            power_scale = W.s * 1e6
+            p_label_txt = 's [$\mu$m]'
+            if plot_moments:
+                group_delay = group_delay * 1e6
+
+        if y_units in ['ev', 'eV']:
+            spec_scale = W.phen
+            f_label_txt = '$E_{photon}$ [eV]'
+            if plot_moments:
+                inst_freq = inst_freq
+        else:
+            spec_scale = W.freq_lamd
+            f_label_txt = '$\lambda$ [nm]'
+            if plot_moments:
+                inst_freq = h_eV_s * speed_of_light * 1e9 / inst_freq
 
     if plot_proj:
         # definitions for the axes
@@ -626,14 +850,16 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
         if log_scale == 1:
             log_scale = 0.01
         wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
-                                       wigner[::downsample, ::downsample], cmap=cmap,
-                                       norm=colors.SymLogNorm(linthresh=wigner_lim * log_scale, linscale=2,
-                                                              vmin=-wigner_lim, vmax=wigner_lim),
-                                       vmax=wigner_lim, vmin=-wigner_lim)
+                                   wigner[::downsample, ::downsample], cmap=cmap,  
+                                   norm=colors.SymLogNorm(linthresh=v_maxabs * log_scale, linscale=2,
+                                                          vmin=v_min, vmax=v_max),
+                                   vmax=v_max, vmin=v_min)
     else:
+        #wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
+        #                          wigner[::downsample, ::downsample], cmap=cmap, vmax=wigner_lim, vmin=-wigner_lim)
         wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
-                                       wigner[::downsample, ::downsample], cmap=cmap, vmax=wigner_lim, vmin=-wigner_lim)
-
+                                       wigner[::downsample, ::downsample], cmap=cmap, vmax=v_max, vmin=v_min, shading='auto')
+    
     if plot_cbar:
         from mpl_toolkits.axes_grid1.inset_locator import inset_axes
         cbaxes = inset_axes(axScatter, width="50%", height="3%", loc=1)
@@ -687,8 +913,8 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
         y_lim_appl.sort()
 
     else:
-        x_lim_appl = (np.amin(power_scale), np.amax(power_scale))
-        y_lim_appl = (np.amin(spec_scale), np.amax(spec_scale))
+        x_lim_appl = np.array((np.amin(power_scale), np.amax(power_scale)))
+        y_lim_appl = np.array((np.amin(spec_scale), np.amax(spec_scale)))
 
     if x_units == 'fs':
         x_lim_appl = np.flipud(x_lim_appl)
@@ -707,14 +933,15 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
         if plot_text:
             axHistx.text(0.02, 0.95, r'E= {:.2e} J'.format(W.energy()), horizontalalignment='left',
                          verticalalignment='top', transform=axHistx.transAxes)  # fontsize=12,
-        axHistx.set_ylabel('Power [W]')
+        # axHistx.set_ylabel('Power [W]')
+        axHistx.set_ylabel('Power\n[arb. units]')
 
         if spec.max() <= 0:
             axHisty.plot(spec, spec_scale)
         else:
             axHisty.plot(spec / spec.max(), spec_scale)
 
-        axHisty.set_xlabel('Spectrum [a.u.]')
+        axHisty.set_xlabel('Spectrum\n[arb. units]')
 
         axScatter.axis('tight')
         axScatter.set_xlabel(p_label_txt)
@@ -734,7 +961,10 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
 
         axHistx.set_xlim(x_lim_appl[0], x_lim_appl[1])
         axHisty.set_ylim(y_lim_appl[0], y_lim_appl[1])
-
+        
+        _logger.debug(ind_str + 'x_lim = {} - {}'.format(x_lim_appl[0], x_lim_appl[1]))
+        _logger.debug(ind_str + 'y_lim = {} - {}'.format(y_lim_appl[0], y_lim_appl[1]))
+        
         if log_scale != 0:
             axHistx.set_ylim(np.nanmin(power), np.nanmax(power))
             axHisty.set_xlim(np.nanmin(spec), np.nanmax(spec))
@@ -745,6 +975,12 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
         axScatter.axis('tight')
         axScatter.set_xlabel(p_label_txt)
         axScatter.set_ylabel(f_label_txt)
+        
+        axScatter.set_xlim(x_lim_appl[0], x_lim_appl[1])
+        axScatter.set_ylim(y_lim_appl[0], y_lim_appl[1])
+        
+        _logger.debug(ind_str + 'x_lim = {} - {}'.format(x_lim_appl[0], x_lim_appl[1]))
+        _logger.debug(ind_str + 'y_lim = {} - {}'.format(y_lim_appl[0], y_lim_appl[1]))
 
     # axScatter.set_xlim(x_lim[0], x_lim[1])
     # axScatter.set_ylim(y_lim[0], y_lim[1])
@@ -756,7 +992,7 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
             save_path = W.filePath + '_wig.' + str(savefig)
             # fig.savefig(W.filePath + '_wig.' + str(savefig), format=savefig)
         else:
-            save_path = W.filePath + '_wig_' + str(W.z) + 'm.' + str(savefig)
+            save_path = W.filePath + '_wig_{:.2f}m.{}'.format(W.z, savefig)
             # fig.savefig(W.filePath + '_wig_' + str(W.z) + 'm.' + str(savefig), format=savefig)
         _logger.debug(ind_str + 'saving to {}'.format(save_path))
         fig.savefig(save_path, format=savefig)
@@ -772,6 +1008,302 @@ def plot_wigner(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, N
         plt.close(fig)
 
 
+@if_plottable
+def plot_wigner_u(wig_or_out, z=np.inf, x_units='um', y_units='ev', x_lim=(None, None), y_lim=(None, None), v_lim=(None, None), downsample=1,
+                autoscale=None, figsize=3, cmap='seismic', fig_name=None, savefig=False, showfig=True,
+                plot_proj=1, plot_text=1, plot_moments=0, plot_cbar=0, log_scale=0, **kwargs):
+    """
+    Plots wigner distribution (WD) with marginals
+
+    :param wig_or_out: may be WignerDistribution() or GenesisOutput() object
+    :param z: (if isinstance(wig_or_out, GenesisOutput)) location at which WD will be calculated
+    :param x_units: [m or fs] units to display power scale
+    :param y_units: [nm or eV] units to display spectrum scale
+    :param x_lim: scaling limits for x in given units, (min,max) or [min,max], e.g: (None,6)
+    :param x_lim: scaling limits for y in given units, (min,max) or [min,max], e.g: (None,6)
+    :param downsample: speeds up plotting by displaying only 1/downsample**2 points
+    :param autoscale: find x_lim and x_lim values automatically. Only (values > max_value * autoscale) will be displayed
+    :param figsize: rescales the size of the figure
+    :param cmap: colormar (http://matplotlib.org/users/colormaps.html)
+    :param fig_name: the desired name of the output figure, would be used as suffix to the image filename if savefig==True
+    :param savefig: bool type variable, allow to save figure to image (savefig='png' (default) or savefig='eps', etc...)
+    :param showfig: bool type variable, allow to display figure (slower)
+    :param plot_proj: plot marginal distributions
+    :param plot_text: show text
+    :param plot_moments: plot moments as lines on top of Wigner distribution
+    :param plot_cbar: plots colorbar
+    :param log_scale: plots wigner distribution in logarithmic scale
+    :param kwargs:
+    :return: None
+    """
+    if showfig == False and savefig == False:
+        return
+    add_prefix = True
+    
+    _logger.info('plotting Wigner distribution')
+    _logger.debug(ind_str + str(type(wig_or_out)))
+    
+    if not hasattr(wig_or_out, 'wig') and hasattr(wig_or_out, 'calc_radsize'):
+        W = wigner_out(wig_or_out, z)
+    elif hasattr(wig_or_out, 'wig'):
+        W = wig_or_out
+    else:
+        raise ValueError('Unknown object for Wigner plot')
+    
+    if fig_name is None:
+        if W.fileName() == '':
+            fig_text = 'Wigner distribution'
+        else:
+            fig_text = 'Wigner distribution ' + W.fileName()
+    else:
+        fig_text = fig_name
+    if W.z != None:
+        fig_text += ' ' + str(W.z) + 'm'
+    
+    if autoscale:
+        fig_text += ' autsc'
+    
+    fig = plt.figure(fig_text)
+    plt.clf()
+    fig.set_size_inches((4.5 * figsize, 3.25 * figsize), forward=True)
+    
+    power = W.proj_s()
+    spec = W.proj_k()
+    wigner = W.wig
+    wigner_lim = np.amax(abs(W.wig))
+    
+    if v_lim[0] is None:
+        v_min = -wigner_lim
+    else:
+        v_min = v_lim[0]
+    
+    if v_lim[1] is None:
+        v_max = wigner_lim
+    else:
+        v_max = v_lim[1]
+        
+    v_maxabs = np.amax([np.abs(v_min), np.abs(v_max)])
+    
+    if plot_moments:
+        inst_freq = W.moment1_k() #TODO:rename
+        group_delay = W.moment1_s()
+    
+    # if W.domain in ['x','y','s']:
+    if isinstance(W, WignerDistributionTransverse):
+        power_scale, power_prefix, power_order = mprefix(W.s, order_bias=0.05, apply=add_prefix)
+        spec_scale, spec_prefix, spec_order = mprefix(W.theta(), order_bias=0.05, apply=add_prefix)
+        p_label_txt = 's [{:}m]'.format(power_prefix)
+        f_label_txt = r'$\theta$ [{:}rad]'.format(spec_prefix)
+        if plot_moments:
+            group_delay = group_delay / 10**power_order
+            inst_freq = k2angle(inst_freq, W.xlamds) / 10**spec_order
+    
+    elif isinstance(W, WignerDistributionLongitudinal):
+        if x_units in ['s','fs']:
+            power_scale, power_prefix, power_order = mprefix(-W.s / speed_of_light, order_bias=0.05, apply=add_prefix)
+            # power_scale = -W.s / speed_of_light * 1e15
+            p_label_txt = 't [{:}s]'.format(power_prefix)
+            if plot_moments:
+                group_delay = -group_dmelay / 10**power_order
+        else:
+            power_scale, power_prefix, power_order = mprefix(W.s, order_bias=0.05, apply=add_prefix)
+            # power_scale = W.s * 1e6
+            p_label_txt = 's [{:}m]'.format(power_prefix)
+            if plot_moments:
+                group_delay = group_delay / 10**power_order
+        if y_units in ['ev', 'eV']:
+            spec_scale, spec_prefix, spec_order = mprefix(W.phen, order_bias=0.05, apply=add_prefix)
+            # spec_scale = W.phen
+            f_label_txt = r'$E_{photon}$'+' [{:}eV]'.format(spec_prefix)
+            if plot_moments:
+                inst_freq = lambda2eV(k2lambda(inst_freq)) / 10**spec_order
+        else:
+            spec_scale, spec_prefix, spec_order = mprefix(W.freq_lamd, order_bias=0.05, apply=add_prefix)
+            # spec_scale = W.freq_lamd
+            f_label_txt = r'$\lambda$ [{:}m]'.format(spec_prefix)
+            if plot_moments:
+                inst_freq = k2lambda(inst_freq) / 10**spec_order
+    
+    if plot_proj:
+        # definitions for the axes
+        left, width = 0.18, 0.57
+        bottom, height = 0.14, 0.55
+        left_h = left + width + 0.02 - 0.02
+        bottom_h = bottom + height + 0.02 - 0.02
+
+        rect_scatter = [left, bottom, width, height]
+        rect_histx = [left, bottom_h, width, 0.2]
+        rect_histy = [left_h, bottom, 0.15, height]
+
+        axHistx = plt.axes(rect_histx)
+        axHisty = plt.axes(rect_histy)
+        axScatter = plt.axes(rect_scatter, sharex=axHistx, sharey=axHisty)
+    else:
+        axScatter = plt.axes()
+    
+    # cmap='RdBu_r'
+    # axScatter.imshow(wigner, cmap=cmap, vmax=wigner_lim, vmin=-wigner_lim)
+    
+    if log_scale != 0:
+        if log_scale == 1:
+            log_scale = 0.01
+        wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
+                                   wigner[::downsample, ::downsample], cmap=cmap,  
+                                   norm=colors.SymLogNorm(linthresh=v_maxabs * log_scale, linscale=2,
+                                                          vmin=v_min, vmax=v_max),
+                                   vmax=v_max, vmin=v_min)
+    else:
+        #wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
+        #                          wigner[::downsample, ::downsample], cmap=cmap, vmax=wigner_lim, vmin=-wigner_lim)
+        wigplot = axScatter.pcolormesh(power_scale[::downsample], spec_scale[::downsample],
+                                       wigner[::downsample, ::downsample], cmap=cmap, vmax=v_max, vmin=v_min, shading='auto')
+    
+    if plot_cbar:
+        from mpl_toolkits.axes_grid1.inset_locator import inset_axes
+        cbaxes = inset_axes(axScatter, width="50%", height="3%", loc=1)
+        fig.colorbar(wigplot, cax=cbaxes, orientation='horizontal')
+    
+    if plot_text:
+        # if hasattr(wig_or_out, 'is_spectrogram'):
+            # if wig_or_out.is_spectrogram:
+                # axScatter.text(0.98, 0.98, 'Spectrogram', horizontalalignment='right', verticalalignment='top',
+                               # transform=axScatter.transAxes, color='red')
+        axScatter.text(0.02, 0.98, r'$W_{{max}}$= {:.2e}'.format(np.amax(wigner)), horizontalalignment='left',
+                       verticalalignment='top', transform=axScatter.transAxes)  # fontsize=12,
+        # if hasattr(W, 'on_axis'):
+            # if W.on_axis == True:
+                # axScatter.text(0.5, 0.98, r"(on axis)", fontsize=10, horizontalalignment='center',
+                               # verticalalignment='top', transform=axScatter.transAxes)
+            # else:
+                # axScatter.text(0.5, 0.98, r"(assuming full spatial coherence)", fontsize=10,
+                               # horizontalalignment='center', verticalalignment='top', transform=axScatter.transAxes)
+    
+    if plot_moments:
+        weight_power = power / np.max(power)
+        weight_power[weight_power < np.nanmax(weight_power) / 1e2] = 0
+        idx_power_fine = np.where(weight_power > np.nanmax(weight_power) / 1e2)
+        weight_spec = spec / np.max(spec)
+        weight_spec[weight_spec < np.nanmax(weight_spec) / 1e2] = 0
+        idx_spec_fine = np.where(weight_spec > np.nanmax(weight_spec) / 1e2)
+
+        plt.scatter(power_scale[idx_power_fine], inst_freq[idx_power_fine], s=weight_power[idx_power_fine], c='black',
+                    linewidths=2)
+        plt.scatter(group_delay[idx_spec_fine], spec_scale[idx_spec_fine], s=weight_spec[idx_spec_fine], c='green',
+                    linewidths=2)
+        # axScatter.plot(power_scale[::downsample], inst_freq[::downsample], "-k")
+        # axScatter.plot(group_delay[::downsample], spec_scale[::downsample], "-g")
+    
+    if autoscale == 1:
+        autoscale = 1e-2
+    
+    if autoscale not in [0, None]:
+        max_power = np.amax(power)
+        max_spectrum = np.amax(spec)
+        idx_p = np.where(power > max_power * autoscale)[0]
+        idx_s = np.where(spec > max_spectrum * autoscale)[0]
+        x_lim_appl = [power_scale[idx_p[0]], power_scale[idx_p[-1]]]
+        x_lim_appl = np.array(x_lim_appl)
+        x_lim_appl.sort()
+        y_lim_appl = [spec_scale[idx_s[0]], spec_scale[idx_s[-1]]]
+        y_lim_appl = np.array(y_lim_appl)
+        y_lim_appl.sort()
+    else:
+        x_lim_appl = np.array((np.amin(power_scale), np.amax(power_scale)))
+        y_lim_appl = np.array((np.amin(spec_scale), np.amax(spec_scale)))
+    
+    
+    if x_units == 'fs':
+        x_lim_appl = np.flipud(x_lim_appl)
+    
+    if x_lim[0] is not None:
+        x_lim_appl[0] = x_lim[0]
+    if x_lim[1] is not None:
+        x_lim_appl[1] = x_lim[1]
+    if y_lim[0] is not None:
+        y_lim_appl[0] = y_lim[0]
+    if y_lim[1] is not None:
+        y_lim_appl[1] = y_lim[1]
+    
+    if plot_proj:
+        axHistx.plot(power_scale, power)
+        # if plot_text:
+            # axHistx.text(0.02, 0.95, r'E= {:.2e} J'.format(W.energy()), horizontalalignment='left',
+                         # verticalalignment='top', transform=axHistx.transAxes)  # fontsize=12,
+        # axHistx.set_ylabel('Power\n[arb. units]')
+        axHistx.set_ylabel('[arb. units]')
+        
+        if spec.max() <= 0:
+            axHisty.plot(spec, spec_scale)
+        else:
+            axHisty.plot(spec / spec.max(), spec_scale)
+
+        # axHisty.set_xlabel('Spectrum\n[arb. units]')
+        axHisty.set_xlabel('[arb. units]')
+
+        axScatter.axis('tight')
+        axScatter.set_xlabel(p_label_txt)
+        axScatter.set_ylabel(f_label_txt)
+
+        axHistx.set_ylim(ymin=0)
+        axHisty.set_xlim(xmin=0)
+
+        for tl in axHistx.get_xticklabels():
+            tl.set_visible(False)
+
+        for tl in axHisty.get_yticklabels():
+            tl.set_visible(False)
+
+        axHistx.yaxis.major.locator.set_params(nbins=4)
+        axHisty.xaxis.major.locator.set_params(nbins=2)
+
+        axHistx.set_xlim(x_lim_appl[0], x_lim_appl[1])
+        axHisty.set_ylim(y_lim_appl[0], y_lim_appl[1])
+        
+        _logger.debug(ind_str + 'x_lim = {} - {}'.format(x_lim_appl[0], x_lim_appl[1]))
+        _logger.debug(ind_str + 'y_lim = {} - {}'.format(y_lim_appl[0], y_lim_appl[1]))
+        
+        if log_scale != 0:
+            axHistx.set_ylim(np.nanmin(power), np.nanmax(power))
+            axHisty.set_xlim(np.nanmin(spec), np.nanmax(spec))
+            axHisty.set_xscale('log')
+            axHistx.set_yscale('log')
+
+    else:
+        axScatter.axis('tight')
+        axScatter.set_xlabel(p_label_txt)
+        axScatter.set_ylabel(f_label_txt)
+        
+        axScatter.set_xlim(x_lim_appl[0], x_lim_appl[1])
+        axScatter.set_ylim(y_lim_appl[0], y_lim_appl[1])
+        
+        _logger.debug(ind_str + 'x_lim = {} - {}'.format(x_lim_appl[0], x_lim_appl[1]))
+        _logger.debug(ind_str + 'y_lim = {} - {}'.format(y_lim_appl[0], y_lim_appl[1]))
+
+    # axScatter.set_xlim(x_lim[0], x_lim[1])
+    # axScatter.set_ylim(y_lim[0], y_lim[1])
+
+    if savefig != False:
+        if savefig == True:
+            savefig = 'png'
+        if W.z is None:
+            save_path = W.filePath + '_wig.' + str(savefig)
+            # fig.savefig(W.filePath + '_wig.' + str(savefig), format=savefig)
+        else:
+            save_path = W.filePath + '_wig_{:.2f}m.{}'.format(W.z, savefig)
+            # fig.savefig(W.filePath + '_wig_' + str(W.z) + 'm.' + str(savefig), format=savefig)
+        _logger.debug(ind_str + 'saving to {}'.format(save_path))
+        fig.savefig(save_path, format=savefig)
+
+    plt.draw()
+
+    if showfig == True:
+        dir = os.path.dirname(W.filePath)
+        rcParams["savefig.directory"] = dir
+        plt.show()
+    else:
+        # plt.close('all')
+        plt.close(fig)
+
 @if_plottable
 def plot_dfl_waistscan(sc_res, fig_name=None, figsize=4, showfig=True, savefig=False):
     _logger.info('plot dfl waist scan')
diff --git a/ocelot/gui/genesis4_plot.py b/ocelot/gui/genesis4_plot.py
index d1fcca95..826a22af 100644
--- a/ocelot/gui/genesis4_plot.py
+++ b/ocelot/gui/genesis4_plot.py
@@ -17,6 +17,7 @@
 
 import sys
 import os
+import glob
 import csv
 import time
 import matplotlib
@@ -71,7 +72,7 @@
 #     return
 
 @if_plottable
-def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 1, 1, 10, 1, 0, 0, 0, 0, 0, 10, 1),
+def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 0, 0, 5, 1, 0, 0, 0, 1, 0, 1, 1),
                       vartype_dfl=complex128, *args, **kwargs):
     debug = 1
     """
@@ -86,15 +87,15 @@ def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 1
         1 - radiation evolution
         2 - profile at z=0m
         3 - profile at the end
-        4 - profile every m meters
+        4 - profile at n equidistant z-points
         5 - dfl at the end, space    -time      domain
         6 -                 inv.space-time      domain
         7 -                 space    -frequency domain
         8 -                 inv.space-frequency domain
         9 - dpa as edist at the end, smeared
         10 - dpa as edist at the end, not smeared
-        11 - wigner distribution every m meters,
-        12 - ebeam bucket at max power
+        11 - wigner distribution at n equidistant z-points,
+        12 - ebeam bucket at max power (not implemented)
     picks as an input "GenesisOutput" object, file path of directory as strings.
     plots e-beam evolution, radiation evolution, initial and final simulation window
     If folder path is provided, all *.gout and *.out files are plotted
@@ -110,9 +111,13 @@ def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 1
         savefig = 'png'
 
     if choice == 'all':
-        choice = (1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 0, 10, 0)
+        choice = (1, 1, 0, 0, 6, 1, 1, 1, 1, 1, 1, 6, 0)
     elif choice == 'gen':
         choice = (1, 1, 1, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0)
+    elif choice == 'dfl':
+        choice = (0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0)
+    elif choice == 'dpa':
+        choice = (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0)
 
     if len(choice) > 13:
         choice = choice[:13]
@@ -123,66 +128,104 @@ def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 1
         handles = []
         for root, dirs, files in os.walk(handle):
             for name in files:
-                if name.endswith('out.h5'):
+                if name.endswith('h5'):
                     handles.append(os.path.join(root, name))
         _logger.info('\n  plotting all files in {}'.format(str(handle)))
+    elif str(handle).endswith('*') and os.path.isdir(os.path.split(handle)[0]):
+        handles = [result for result in glob.iglob(handle) if result.endswith('.h5')] # search with wildcharacter ending
     else:
         handles = [handle]
+    
+    # for handle in handles:
+        # try_filename_fld = handle.replace('.out.h5', '.fld.h5')
+        # if os.path.isfile(try_filename_fld):
+            # handles.append(try_filename_fld)
+        # try_filename_par = handle.replace('.out.h5', '.par.h5')
+        # if os.path.isfile(try_filename_par):
+            # handles.append(try_filename_par)
+    #TODO: check if there are filed with stripped .out.h5 and added .fld.h5
+    
+    if len(handles) > 1:
+        handles = sorted(handles)
+        handles = [h for h in handles if ".out." in h] + [h for h in handles if ".out." not in h] #plotting .out first
 
     for handle in handles:
-
+        _logger.debug('checking ' + str(handle))
         if os.path.isfile(str(handle)):
             _logger.info('plotting ' + str(handle))
-            try:
-                handle = read_gout4(handle)
-            except (IOError, ValueError):
+            if handle.endswith('out.h5'):
+                try:
+                    handle = read_gout4(handle)
+                except (IOError, ValueError):
+                    _logger.debug('could not read ' + str(handle))
+                    pass
+                
+            elif handle.endswith('fld.h5'):
+                try: 
+                    handle = read_dfl4(handle)
+                except (IOError, ValueError):
+                    _logger.debug('could not read ' + str(handle))
+                    pass
+                
+            elif handle.endswith('par.h5'):
+                try:            
+                    handle = read_dpa4(handle, partskip=100)
+                except (IOError, ValueError):
+                    _logger.debug('could not read ' + str(handle))
+                    pass
+            
+            else:
                 continue
-
+            
         if isinstance(handle, Genesis4Output):
             if choice[0]:
-                f0 = plot_gen4_out_e(handle, showfig=showfig, savefig=savefig, debug=debug)
+                f0 = plot_gen4_out_e(handle, showfig=showfig, savefig=savefig)
             if choice[1]:
-                f1 = plot_gen4_out_ph(handle, showfig=showfig, savefig=savefig, debug=debug)
+                f1 = plot_gen4_out_ph(handle, showfig=showfig, savefig=savefig)
             if choice[2]:
-                f2 = plot_gen4_out_z(handle, z=0, showfig=showfig, savefig=savefig, debug=debug)
+                f2 = plot_gen4_out_z(handle, z=0, showfig=showfig, savefig=savefig)
             if choice[3]:
-                f3 = plot_gen4_out_z(handle, z=np.inf, showfig=showfig, savefig=savefig, debug=debug)
-            if choice[11] != 0:
-                if choice[11] == -1:
-                    # try:
-                    W = wigner_out(handle, pad=2)
-                    plot_wigner(W, showfig=showfig, savefig=savefig, debug=debug, downsample=2)
-                    # except:
-                    # _logger.warning('could not plot wigner')
+                f3 = plot_gen4_out_z(handle, z=np.inf, showfig=showfig, savefig=savefig)
+            if choice[4] != 0:
+                if choice[4] != []:
+                    if choice[4] == 1:
+                        z_arr = [np.amax(handle.z)]
+                    else:
+                        z_arr = np.linspace(0, np.amax(handle.z), choice[4])
                 else:
+                    z_arr = choice[4]
+                for z in z_arr:
+                    plot_gen4_out_z(handle, z=z, showfig=showfig, savefig=savefig, debug=debug, *args, **kwargs)
+            if choice[11] != 0:
+                if choice[11] != []:
                     if choice[11] == 1:
-                        _logger.warning(
-                            'choice[11] in plot_gen_out_all defines interval of Wigner plotting. To plot at the end set to "-1"')
-                    # try:
-                    for z in np.arange(0, np.amax(handle.z), choice[11]):
-                        W = wigner_out(handle, z=z, pad=2)
-                        plot_wigner(W, showfig=showfig, savefig=savefig, debug=debug, downsample=2)
-                    W = wigner_out(handle, z=np.inf, pad=2)
+                        z_arr = [np.amax(handle.z)]
+                    else:
+                        z_arr = np.linspace(0, np.amax(handle.z), choice[11])
+                else:
+                    z_arr = choice[11]
+                for z in z_arr:
+                    W = wigner_out(handle, z=z, pad=1)
                     plot_wigner(W, showfig=showfig, savefig=savefig, debug=debug, downsample=2)
                     # except:
                     # _logger.warning('could not plot wigner')
             # if choice[4] != 0:
             # for z in np.arange(choice[4], np.amax(handle.z), choice[4]):
             # plot_gen4_out_z(handle, z=z, showfig=showfig, savefig=savefig, debug=debug)
-            if choice[4] != 0 and choice[4] != []:
-                for z in np.arange(choice[4], np.amax(handle.z), choice[4]):
-                    plot_gen4_out_z(handle, z=z, showfig=showfig, savefig=savefig, debug=debug, *args, **kwargs)
 
-            if choice[12]:
-                pass
+            # if choice[12]:
+                # pass
                 # try:
                 # plot_dpa_bucket_out(handle,scatter=0,slice_pos='max_P',repeat=3, showfig=showfig,
                 # savefig=savefig, cmap=def_cmap)
                 # except IOError:
                 # pass
 
-        if os.path.isfile(handle.filePath.replace('.out.h5', '.fld.h5')) and any(choice[5:8]):
-            dfl = read_dfl4(handle.filePath.replace('.out.h5', '.fld.h5'))
+        if isinstance(handle, RadiationField) and any(choice[5:8]):
+            _logger.info('processing RadiationField')
+        # if os.path.isfile(handle.filePath.replace('.out.h5', '.fld.h5')) and any(choice[5:8]):
+            # dfl = read_dfl4(handle.filePath.replace('.out.h5', '.fld.h5'))
+            dfl = handle
             if dfl.Nz() == 0:
                 _logger.warning('empty dfl, skipping')
             else:
@@ -195,18 +238,28 @@ def plot_gen4_out_all(handle=None, savefig='png', showfig=False, choice=(1, 1, 1
                 if choice[8]:
                     f8 = plot_dfl(dfl, domains='kf', auto_zoom=0, showfig=showfig, savefig=savefig, debug=debug)
 
-        if os.path.isfile(handle.filePath.replace('.out.h5', '.par.h5')) and (choice[9] or choice[10]):
-            dpa = read_dpa4(handle.filePath.replace('.out.h5', '.par.h5'))
+        if isinstance(handle, Genesis4ParticlesDump) and any(choice[9:10]):
+            _logger.info('processing Genesis4ParticlesDump')
+            #if os.path.isfile(handle.filePath.replace('.out.h5', '.par.h5')) and (choice[9] or choice[10]):
+                #dpa = read_dpa4(handle.filePath.replace('.out.h5', '.par.h5'),  estimate_npart=1, partskip=100)
             if choice[9]:
                 try:
-                    edist = dpa42edist(dpa, n_part=5e4, fill_gaps=1)
+                    if handle.one4one:
+                        edist = dpa42edist(handle)
+                    else:
+                        edist = dpa42edist(handle, n_part=5e4, fill_gaps=1)
+                        
                     f9 = plot_edist(edist, figsize=3, fig_name=None, savefig=savefig, showfig=showfig, bins=100,
                                     debug=debug)
                 except:
                     _logger.warning('could not plot smeared edist')
             if choice[10]:
                 try:
-                    edist = dpa42edist(dpa, n_part=5e4, fill_gaps=0)
+                    if handle.one4one:
+                        edist = dpa42edist(handle)
+                    else:
+                        edist = dpa42edist(handle, n_part=5e4, fill_gaps=1)
+                        
                     f10 = plot_edist(edist, figsize=3, fig_name=None, savefig=savefig, showfig=showfig,
                                      bins=(50, 50, 300, 300), debug=debug)
                 except:
@@ -367,7 +420,7 @@ def plot_gen4_out_z(out, z=np.inf, params=['rad_power+el_current', 'el_energy+el
     if savefig != False:
         if savefig == True:
             savefig = 'png'
-        fig.savefig(out.filePath + '_z_' + str(z) + 'm.' + str(savefig), format=savefig)
+        fig.savefig(out.filePath + '_z_{:.2f}m.{}'.format(z,savefig), format=savefig)
 
     if showfig:
         plt.show()
@@ -888,14 +941,25 @@ def subfig_evo_el_energy(ax_energy, out, legend):
     z = out.h5['Lattice/zplot']
     el_energy_spread = out.h5['Beam/energyspread'][:]
 
-    ax_energy.plot(z, np.average(el_energy - el_energy_av, axis=1), 'b-', linewidth=1.5)
+    mean_energy = np.nanmean(el_energy - el_energy_av, axis=1)
+    ax_energy.plot(z, mean_energy, 'b-', linewidth=1.5)
     ax_energy.set_ylabel('<E> + ' + str(el_energy_av) + '[MeV]')
     ax_energy.ticklabel_format(axis='y', style='sci', scilimits=(-3, 3), useOffset=False)
     ax_energy.grid(True)
 
+    #notnan_idx = np.isnan(el_energy_spread) == False
+    
+    I_weight = out.I / np.sum(out.I)
+    
+    
+    #mean_spread = np.average(el_energy_spread[notnan_idx], weights=out.I, axis=1)
+    
+    mean_spread = np.nansum(el_energy_spread * I_weight[np.newaxis, :], axis=1) * m_e_MeV
+    max_spread = np.nanmax(el_energy_spread, axis=1)* m_e_MeV
+    
     ax_spread = ax_energy.twinx()
-    ax_spread.plot(z, np.average(el_energy_spread * m_e_MeV, weights=out.I, axis=1), 'm--', out.z,
-                   np.amax(el_energy_spread * m_e_GeV * 1000, axis=1), 'r--', linewidth=1.5)
+    ax_spread.plot(z, mean_spread, 'm--', 
+                z, max_spread, 'r--', linewidth=1.5)
     ax_spread.set_ylabel(r'$\sigma_E$ [MeV]')
     ax_spread.grid(False)
     ax_spread.set_ylim(ymin=0)
@@ -916,7 +980,11 @@ def subfig_evo_el_bunching(ax_bunching, out, legend):
     z = out.h5['Lattice/zplot']
     b = out.h5['Beam/bunching']
 
-    ax_bunching.plot(z, np.average(b, weights=out.I, axis=1), 'k-', out.z, np.amax(b, axis=1), 'grey', linewidth=1.5)
+    
+    I_weight = out.I / np.sum(out.I)
+    mean_bunching = np.nansum(b * I_weight[np.newaxis, :], axis=1)
+    
+    ax_bunching.plot(z, mean_bunching, 'k-', out.z, np.nanmax(b, axis=1), 'grey', linewidth=1.5)
     # ax_bunching.plot(out.z, np.amax(out.bunching, axis=0), 'grey',linewidth=1.5) #only max
     ax_bunching.set_ylabel(r'Bunching')
     ax_bunching.set_ylim(ymin=0)
@@ -924,7 +992,6 @@ def subfig_evo_el_bunching(ax_bunching, out, legend):
     ax_bunching.yaxis.major.locator.set_params(nbins=number_ticks)
     ax_bunching.grid(True)
 
-
 @if_plottable
 def subfig_evo_rad_pow_en(ax_rad_pow, out, legend, log=1):
     if log:
@@ -1075,7 +1142,8 @@ def subfig_rad_size(ax_size_t, out, legend):
     y_size = out.h5['Field/ysize'][:]
     r_size = np.sqrt(x_size ** 2 + y_size ** 2)
 
-    if out.nSlices == 1:
+    # if out.nSlices == 1:
+    if out.tdp == 0:
         ax_size_t.plot(out.z, r_size * 2 * 1e6, 'b-', linewidth=1.5)
         #        ax_size_t.plot([np.amin(out.z), np.amax(out.z)], [out.leng * 1e6, out.leng * 1e6], 'b-', linewidth=1.0)
         ax_size_t.set_ylabel('transverse $[\mu m]$')
@@ -1085,7 +1153,7 @@ def subfig_rad_size(ax_size_t, out, legend):
         else:
             if np.amax(out.rad_power) > 0:
                 # idx = out.rad_energy != 0
-                weight = out.rad_power + np.amin(out.rad_power[out.rad_power != 0]) / 1e6
+                weight = out.rad_power + np.amin(np.greater(out.rad_power,[0])) / 1e6
                 weight[out.rad_energy == 0, :] = 1
                 r_size = np.average(r_size * 2 * 1e6, weights=weight, axis=1)
             else:
@@ -1100,7 +1168,7 @@ def subfig_rad_size(ax_size_t, out, legend):
     ax_size_t.grid(True)
     plt.yticks(plt.yticks()[0][0:-1])
 
-    if out.nSlices > 1:
+    if out.tdp == 1:
         ax_size_s = ax_size_t.twinx()
         size_long_fwhm = np.zeros_like(out.z)
         size_long_std = np.zeros_like(out.z)
@@ -1185,3 +1253,136 @@ def subfig_evo_rad_spec_sz(ax_spectrum_evo, out, legend, norm=1):
         ax_spectrum_evo.grid(True)
     else:
         pass
+
+def plot_dpa4_bucket(dpa, slice_num=None, repeat=1, GeV=1, figsize=4, cmap=def_cmap, scatter=False, energy_mean=None,
+                    legend=True, fig_name=None, savefig=False, showfig=True, suffix='', bins=(50, 50), debug=1,
+                    return_mode_gamma=0):
+    part_colors = ['darkred', 'orange', 'g', 'b', 'm', 'c', 'y', 'olive']
+    # cmap='BuPu'
+    y_bins = bins[0]
+    z_bins = bins[1]
+    
+    if not dpa.one4one:
+        return
+    
+    if showfig == False and savefig == False:
+        return
+    
+    _logger.info('plotting dpa bucket')
+    start_time = time.time()
+    
+    # if dpa.__class__ != GenesisParticlesDump:
+    #     raise ValueError('wrong particle object: should be GenesisParticlesDump')
+    
+    if dpa.slicelist.shape == 1:
+        slice_num = 0
+    if slice_num is None:
+        slice_num = dpa.slicelist[int(dpa.slicelist.size/2)]
+        _logger.debug(
+            ind_str + 'no slice number provided, using middle of the distribution - slice number {}'.format(slice_num))
+    else:
+        assert (slice_num <= np.shape(dpa.ph)[0]), 'slice_num larger than the dpa shape'
+    
+    if fig_name == None:
+        fig_name = 'Electron phase space ' + dpa.fileName()
+    fig = plt.figure(fig_name)
+    fig.clf()
+    fig.set_size_inches((5 * figsize, 3 * figsize), forward=True)
+    
+    left, width = 0.18, 0.57
+    bottom, height = 0.14, 0.55
+    left_h = left + width + 0.02 - 0.02
+    bottom_h = bottom + height + 0.02 - 0.02
+    
+    rect_scatter = [left, bottom, width, height]
+    rect_histx = [left, bottom_h, width, 0.2]
+    rect_histy = [left_h, bottom, 0.15, height]
+    
+    ax_main = plt.axes(rect_scatter)
+    ax_z_hist = plt.axes(rect_histx, sharex=ax_main)
+    ax_y_hist = plt.axes(rect_histy, sharey=ax_main)
+    
+    # ax_z_hist = plt.subplot2grid((4, 1), (0, 0), rowspan=1)
+    # ax_y_hist = plt.subplot2grid((4, 1), (0, 0), rowspan=1)
+    
+    # ax_main = plt.subplot2grid((4, 1), (1, 0), rowspan=3, sharex=ax_z_hist)
+    
+    nbins = np.shape(dpa.ph)[1]
+    phase = deepcopy(dpa.ph[slice_num, :, :])
+    energy = deepcopy(dpa.e[slice_num, :, :])
+    _logger.debug(ind_str + 'nbins =  {}'.format(nbins))
+    
+    # checking for lost particles
+    if np.any(energy<0):
+        particle_present_idx = energy>0
+        energy = energy[particle_present_idx]
+        phase = phase[particle_present_idx]
+    
+    if GeV:
+        energy *= m_e_MeV
+        if energy_mean == None:
+            energy_mean = round(np.mean(energy), 0)
+    else:
+        if energy_mean == None:
+            energy_mean = round(np.mean(energy), 1)
+    energy -= energy_mean
+    
+    phase_flat = phase.flatten()
+    energy_flat = energy.flatten()
+    for irep in range(repeat - 1):
+        phase_flat = np.append(phase_flat, phase.flatten() + 2 * np.pi * (irep + 1))
+        energy_flat = np.append(energy_flat, energy.flatten())
+    
+    # phase_hist = np.ravel(phase)
+    # for irep in range(repeat-1):
+    #     phase_hist = np.concatenate((phase_hist, np.ravel(phase) + 2 * np.pi * (irep+1)))
+    
+    # hist, edges = np.histogram(phase_hist, bins=50 * repeat)  # calculate current histogram
+    hist_z, edges_z = np.histogram(phase_flat, bins=z_bins * repeat)  # calculate current histogram
+    edges_z = edges_z[0:-1]  # remove the last bin edge to save equal number of points
+    ax_z_hist.bar(edges_z, hist_z, width=edges_z[1] - edges_z[0], color='silver')
+    ax_z_hist.set_ylabel('counts')
+    
+    hist_y, edges_y = np.histogram(energy_flat, bins=y_bins)  # calculate energy histogram
+    edges_y = edges_y[0:-1]  # remove the last bin edge to save equal number of points
+    ax_y_hist.barh(edges_y, hist_y, height=edges_y[1] - edges_y[0], color='silver')
+    ax_y_hist.set_xlabel('counts')
+    
+    for label in ax_z_hist.get_xticklabels():
+        label.set_visible(False)
+    
+    for label in ax_y_hist.get_yticklabels():
+        label.set_visible(False)
+    
+    if scatter == True:
+        _logger.debug(ind_str + 'plotting scatter')
+        for irep in range(repeat):
+            for ibin in range(nbins):
+                ax_main.scatter(phase[ibin, :] + 2 * np.pi * (irep), energy[ibin, :], color=part_colors[ibin],
+                                marker='.')
+    
+        # ax_z_hist.set_xlim([edges[0], edges[-1]])
+    
+    elif scatter == False:
+        _logger.debug(ind_str + 'plotting colormesh')
+        ax_main.hist2d(phase_flat, energy_flat, bins=[z_bins * repeat, y_bins], cmin=0, cmap=cmap)
+    
+    ax_main.set_xlabel('$\phi$ [rad]')
+    if GeV:
+        ax_main.set_ylabel('E [MeV] + ' + str(energy_mean / 1000) + ' [GeV]')
+    else:
+        ax_main.set_ylabel('$\gamma$ + ' + str(energy_mean))
+    
+    plt.draw()
+    if savefig != False:
+        if savefig == True:
+            savefig = 'png'
+        _logger.debug(ind_str + 'saving to {}'.format(dpa.fileName() + suffix + '.' + savefig))
+        plt.savefig(dpa.filePath + suffix + '.' + savefig, format=savefig)
+    
+    if showfig:
+        rcParams["savefig.directory"] = os.path.dirname(dpa.filePath)
+        plt.show()
+    else:
+        # plt.close('all')
+        plt.close(fig)
\ No newline at end of file
diff --git a/ocelot/gui/genesis_plot.py b/ocelot/gui/genesis_plot.py
index d8da0855..f8af2d5a 100644
--- a/ocelot/gui/genesis_plot.py
+++ b/ocelot/gui/genesis_plot.py
@@ -34,7 +34,7 @@
 from ocelot.gui.colormaps2d.colormap2d import *
 from ocelot.gui.settings_plot import *
 from ocelot.gui.dfl_plot import *  # tmp
-from ocelot.gui.beam_plot import plot_beam  # tmp
+from ocelot.gui.beam_plot import plot_beam # tmp
 
 # from pylab import rc, rcParams #tmp
 
@@ -107,7 +107,7 @@ def plot_gen_out_all(handle=None, savefig='png', showfig=False, choice='all', va
 
     # plt.ioff()
 
-    if savefig is True:
+    if savefig == True:
         savefig = 'png'
 
     if choice == 'all':
@@ -205,7 +205,7 @@ def plot_gen_out_all(handle=None, savefig='png', showfig=False, choice='all', va
                     f10 = plot_edist(edist, figsize=3, fig_name=None, savefig=savefig, showfig=showfig,
                                      bins=(100, 100, 100, 100), debug=debug)
 
-    if savefig is not False:
+    if savefig != False:
         _logger.info(ind_str + 'plots recorded to *.' + str(savefig) + ' files')
 
     if showfig:
@@ -243,7 +243,7 @@ def plot_gen_out_z(g, z=np.inf, params=['rad_power+el_current', 'el_energy+el_es
 
     import matplotlib.ticker as ticker
 
-    if showfig is False and savefig is False:
+    if showfig == False and savefig == False:
         return
 
     t_domain = ['rad_power+el_current', 'el_energy+el_espread+el_bunching', 'el_energy+el_espread', 'rad_phase']
@@ -279,7 +279,7 @@ def plot_gen_out_z(g, z=np.inf, params=['rad_power+el_current', 'el_energy+el_es
     # add check for output object
 
     # if fig_name is None:
-    #     if g.fileName() == '':
+    #     if g.fileName() is '':
     #         fig = plt.figure(params_str)
     #         if debug > 0:
     #             print('    plotting ' + params_str)
@@ -291,7 +291,7 @@ def plot_gen_out_z(g, z=np.inf, params=['rad_power+el_current', 'el_energy+el_es
     #     fig = plt.figure(fig_name)
     #     if debug > 0:
     #         print('    plotting ' + fig_name)
-    if fig_name is None:
+    if fig_name == None:
         if g.fileName() == '':
             fig = plt.figure('Bunch profile at z={:.3f} [m]'.format(z))
         else:
@@ -342,7 +342,7 @@ def plot_gen_out_z(g, z=np.inf, params=['rad_power+el_current', 'el_energy+el_es
             # print('! wrong parameter ' + param)
 
     for axi in ax:
-        if axi is not ax[-1]:
+        if axi != ax[-1]:
             axi.set_xlabel('')
             for label in axi.get_xticklabels():
                 label.set_visible(False)
@@ -370,14 +370,14 @@ def plot_gen_out_z(g, z=np.inf, params=['rad_power+el_current', 'el_energy+el_es
             pos1 = axi.get_position()  # get the original position
             pos2 = [pos1.x0 + 0, pos1.y0 - 0.1, pos1.width / 1.0, pos1.height / 1.0]
             axi.set_position(pos2)
-            if axi is not ax[-1]:
+            if axi != ax[-1]:
                 axi.set_xlabel('')
                 for label in axi.get_xticklabels():
                     label.set_visible(False)
 
     plt.draw()
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         fig.savefig(g.filePath + '_z_' + str(z) + 'm.' + str(savefig), format=savefig)
 
@@ -405,7 +405,7 @@ def subfig_z_power_curr(ax_curr, g, zi=None, x_units='um', legend=False, *args,
     else:
         raise ValueError('Unknown parameter x_units (should be um or fs)')
 
-    if zi is None:
+    if zi == None:
         zi = -1
 
     ax_curr.plot(x, g.I / 1e3, 'k--')
@@ -536,7 +536,7 @@ def subfig_z_phase(ax_phase, g, zi=None, x_units='um', legend=False, *args, **kw
     else:
         raise ValueError('Unknown parameter x_units (should be um or fs)')
 
-    if zi is None:
+    if zi == None:
         zi = -1
 
     if "rewrap" in kwargs:
@@ -582,39 +582,41 @@ def subfig_z_phase(ax_phase, g, zi=None, x_units='um', legend=False, *args, **kw
 def subfig_z_spec(ax_spectrum, g, zi=None, y_units='ev', estimate_ph_sp_dens=True, legend=False, *args, **kwargs):
     number_ticks = 6
     # n_pad = 1
-
+    
     mode = kwargs.get('mode', 'mid')
     mode = kwargs.get('spec_mode', mode)
-
-    if zi is None:
+    
+    if zi == None:
         zi = -1
-
+    
+    npad = kwargs.get('spec_npad', 0)
+    
     if hasattr(g, 'spec'):
         if g.spec_mode != mode:
-            g.calc_spec(mode=mode)
+            g.calc_spec(mode=mode, npad=npad)
     else:
-        g.calc_spec(mode=mode)
+        g.calc_spec(mode=mode, npad=npad)
     # TMP
     # g.calc_spec(mode='int')
 
     if 'spec' not in dir(g):
         g.calc_spec()
-
+    
     if y_units == 'nm':
         x = g.freq_lamd
     elif y_units in ['ev', 'eV']:
         x = g.freq_ev
-
+    
     if estimate_ph_sp_dens:
         y_units = 'ev'
         spec = g.spec_phot_density[:, zi]
         # spec = calc_ph_sp_dens(g.spec[:, zi], g.freq_ev, g.n_photons[zi])
     else:
         spec = g.spec[:, zi]
-
+    
     # power = np.pad(g.p_mid, [(int(g.nSlices / 2) * n_pad, (g.nSlices - (int(g.nSlices / 2)))) * n_pad, (0, 0)], mode='constant')
     # phase = np.pad(g.phi_mid, [(int(g.nSlices / 2) * n_pad, (g.nSlices - (int(g.nSlices / 2)))) * n_pad, (0, 0)], mode='constant')  # not supported by the numpy 1.6.2
-
+    
     ax_spectrum.plot(x, spec, 'r-')
     if kwargs.get('showtext', True):
         if mode == 'mid':
@@ -625,7 +627,7 @@ def subfig_z_spec(ax_spectrum, g, zi=None, y_units='ev', estimate_ph_sp_dens=Tru
             ax_spectrum.text(0.98, 0.98, r'(integrated assuming on-axis phases)', fontsize=10,
                              horizontalalignment='right', verticalalignment='top',
                              transform=ax_spectrum.transAxes)  # horizontalalignment='center', verticalalignment='center',
-
+    
     ax_spectrum.set_ylim(ymin=0)
     ax_spectrum.get_yaxis().get_major_formatter().set_useOffset(False)
     ax_spectrum.get_yaxis().get_major_formatter().set_scientific(True)
@@ -633,28 +635,28 @@ def subfig_z_spec(ax_spectrum, g, zi=None, y_units='ev', estimate_ph_sp_dens=Tru
     ax_spectrum.grid(kwargs.get('grid', True))
     if np.amin(x) != np.amax(x):
         ax_spectrum.set_xlim([np.amin(x), np.amax(x)])
-
+    
     maxspectrum_index = np.argmax(spec)
     # maxspower_index = np.argmax(power[:, zi])
     maxspectrum_value = x[maxspectrum_index]
-
+    
     spec_width = None
     if np.sum(spec) != 0:
         pos, width, arr = fwhm3(spec)
-        if width is not None:
+        if width != None:
             if arr[0] == arr[-1]:
                 dx = abs(x[pos] - x[pos - 1])
             else:
                 dx = abs((x[arr[0]] - x[arr[-1]]) / (arr[0] - arr[-1]))
             spec_width = dx * width / x[
                 pos]  # the FWHM of spectral line (error when peakpos is at the edge of lamdscale)
-
-    if spec_width is not None and maxspectrum_value is not None:
+    
+    if spec_width != None and maxspectrum_value != None:
         if y_units == 'nm':
             if kwargs.get('showtext', True):
                 ax_spectrum.text(0.02, 0.98,
                                  r"$\lambda^{max}$= %.4e m " "\n" "$(\Delta\lambda/\lambda)_{fwhm}$= %.2e" % (
-                                     maxspectrum_value * 1e-9, spec_width), fontsize=12, horizontalalignment='left',
+                                 maxspectrum_value * 1e-9, spec_width), fontsize=12, horizontalalignment='left',
                                  verticalalignment='top', transform=ax_spectrum.transAxes,
                                  color='red')  # horizontalalignment='center', verticalalignment='center',
             if estimate_ph_sp_dens:
@@ -665,7 +667,7 @@ def subfig_z_spec(ax_spectrum, g, zi=None, y_units='ev', estimate_ph_sp_dens=Tru
         elif y_units in ['ev', 'eV']:
             if kwargs.get('showtext', True):
                 ax_spectrum.text(0.02, 0.98, r"$E_{ph}^{max}$= %.2f eV " "\n" "$(\Delta E/E)_{fwhm}$= %.2e" % (
-                    maxspectrum_value, spec_width), fontsize=12, horizontalalignment='left', verticalalignment='top',
+                maxspectrum_value, spec_width), fontsize=12, horizontalalignment='left', verticalalignment='top',
                                  transform=ax_spectrum.transAxes,
                                  color='red')  # horizontalalignment='center', verticalalignment='center',
             if estimate_ph_sp_dens:
@@ -674,7 +676,7 @@ def subfig_z_spec(ax_spectrum, g, zi=None, y_units='ev', estimate_ph_sp_dens=Tru
                 ax_spectrum.set_ylabel(r'P($E_{ph}$) [a.u.]')
             ax_spectrum.set_xlabel(r'$E_{photon}$ [eV]')
         # ax_spectrum.text(0.02, 0.98, r"$\lambda_{max}$= %.4e m " "\n" "$(\Delta\lambda/\lambda)_{fwhm}$= %.2e" % (maxspectrum_value, spec_width), fontsize=12, horizontalalignment='left', verticalalignment='top', transform=ax_spectrum.transAxes, color='red')  # horizontalalignment='center', verticalalignment='center',
-
+    
     ax_spectrum.yaxis.major.locator.set_params(nbins=number_ticks)
     ax_spectrum.tick_params(axis='y', which='both', colors='r')
     ax_spectrum.yaxis.label.set_color('r')
@@ -687,10 +689,10 @@ def plot_gen_out_z_old(g, figsize=(10, 14), x_units='um', y_units='ev', legend=T
     print('soon this function will be replaced by plot_gen_out_z_new (currently being tested)')
     number_ticks = 6
 
-    if showfig is False and savefig is False:
+    if showfig == False and savefig == False:
         return
 
-    if g('itdp') is False:
+    if g('itdp') == False:
         print('    plotting bunch profile at ' + str(z) + ' [m]')
         print('!     not applicable for steady-state')
         return
@@ -716,7 +718,7 @@ def plot_gen_out_z_old(g, figsize=(10, 14), x_units='um', y_units='ev', legend=T
         print('    plotting bunch profile at ' + str(z) + ' [m]')
 
     font_size = 1
-    if fig_name is None:
+    if fig_name == None:
         if g.fileName() == '':
             fig = plt.figure('Bunch profile at ' + str(z) + 'm')
         else:
@@ -833,9 +835,9 @@ def plot_gen_out_z_old(g, figsize=(10, 14), x_units='um', y_units='ev', legend=T
             spectrum_lamdwidth_fwhm = dlambda * width / g.freq_lamd[
                 pos]  # the FWHM of spectral line (error when peakpos is at the edge of lamdscale)
 
-    if spectrum_lamdwidth_fwhm is not None and maxspectrum_wavelength is not None:
+    if spectrum_lamdwidth_fwhm != None and maxspectrum_wavelength != None:
         ax_spectrum.text(0.02, 0.98, r"$\lambda_{max}$= %.4e m " "\n" "$(\Delta\lambda/\lambda)_{fwhm}$= %.2e" % (
-            maxspectrum_wavelength, spectrum_lamdwidth_fwhm), fontsize=12, horizontalalignment='left',
+        maxspectrum_wavelength, spectrum_lamdwidth_fwhm), fontsize=12, horizontalalignment='left',
                          verticalalignment='top', transform=ax_spectrum.transAxes,
                          color='red')  # horizontalalignment='center', verticalalignment='center',
 
@@ -889,8 +891,8 @@ def plot_gen_out_z_old(g, figsize=(10, 14), x_units='um', y_units='ev', legend=T
     ax_spectrum.yaxis.get_offset_text().set_color(ax_spectrum.yaxis.label.get_color())
 
     plt.draw()
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         fig.savefig(g.filePath + '_z_' + str(z) + 'm.' + str(savefig), format=savefig)
 
@@ -936,7 +938,7 @@ def plot_gen_out_evo(g, params=['und_quad', 'el_size', 'el_pos', 'el_energy', 'e
     """
     import matplotlib.ticker as ticker
 
-    if showfig is False and savefig is False:
+    if showfig == False and savefig == False:
         return
 
     params_str = str(params).replace("'", '').replace('[', '').replace(']', '').replace(' ', '').replace(',', '--')
@@ -988,6 +990,29 @@ def plot_gen_out_evo(g, params=['und_quad', 'el_size', 'el_pos', 'el_energy', 'e
         elif param.startswith('el_bunching_h'):
             bunch_harm = int(param.replace('el_bunching_h', ''))
             subfig_evo_el_bunching(ax[-1], g, legend, harm=bunch_harm, **kwargs)
+        
+        elif param.startswith('rad_pow') and not 'evo' in param:
+            if 'log' in param:
+                plot_log=1
+            else:
+                plot_log=0
+            
+            if '_h' in param:
+                import re
+                regex = re.compile('_h([0-9]*)')
+                harm = int(regex.findall(param)[-1])
+            else:
+                harm=1
+            
+            if 'en' in param:
+                if not is_tdp:
+                    subfig_evo_rad_pow(ax[-1], g, legend, log=plot_log, harm=harm, **kwargs)
+                else:
+                    subfig_evo_rad_pow_en(ax[-1], g, legend, log=plot_log, harm=harm, **kwargs)
+            else:
+                subfig_evo_rad_pow(ax[-1], g, legend, log=plot_log, harm=harm, **kwargs)
+                
+        
         elif param == 'rad_pow_en_log':
             if not is_tdp:
                 subfig_evo_rad_pow(ax[-1], g, legend, **kwargs)
@@ -998,6 +1023,7 @@ def plot_gen_out_evo(g, params=['und_quad', 'el_size', 'el_pos', 'el_energy', 'e
                 subfig_evo_rad_pow(ax[-1], g, legend, log=0, **kwargs)
             else:
                 subfig_evo_rad_pow_en(ax[-1], g, legend, log=0, **kwargs)
+        
         elif param == 'rad_pow_log':
             subfig_evo_rad_pow(ax[-1], g, legend, **kwargs)
         elif param == 'rad_pow_lin':
@@ -1033,8 +1059,8 @@ def plot_gen_out_evo(g, params=['und_quad', 'el_size', 'el_pos', 'el_energy', 'e
         for label in axi.get_xticklabels():
             label.set_visible(False)
 
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         if fig_name == 'Electrons':
             savepath = g.filePath + '_elec.' + str(savefig)
@@ -1048,7 +1074,7 @@ def plot_gen_out_evo(g, params=['und_quad', 'el_size', 'el_pos', 'el_energy', 'e
         fig.savefig(savepath, format=savefig)
 
     plt.draw()
-    if showfig is True:
+    if showfig == True:
         dir_lst = g.filePath.split(os.path.sep)
         dir = os.path.sep.join(dir_lst[0:-1]) + os.path.sep
         rcParams["savefig.directory"] = dir
@@ -1184,12 +1210,26 @@ def subfig_evo_el_bunching(ax_bunching, g, legend, harm=1, **kwargs):
 
 
 @if_plottable
-def subfig_evo_rad_pow_en(ax_rad_pow, g, legend, log=1, **kwargs):
-    ax_rad_pow.plot(g.z, np.amax(g.p_int, axis=0), 'g-', linewidth=1.5)
-    ax_rad_pow.set_ylabel(r'P [W]')
+def subfig_evo_rad_pow_en(ax_rad_pow, g, legend, log=1, harm=1, **kwargs):
+    if harm == 1:
+        power = g.p_int
+        energy = g.pulse_energy
+        suff = ''
+    else:
+        try:
+            power = getattr(g, 'h{}_power'.format(harm))
+            energy = np.sum(power * g.dt, axis=0)
+            suff = '  (harm {})'.format(harm)
+        except:
+            power = np.zeros_like(g.p_int)
+            energy = np.zeros_like(g.pulse_energy)
+            suff = ''
+    
+    ax_rad_pow.plot(g.z, np.amax(power, axis=0), 'g-', linewidth=1.5)
+    ax_rad_pow.set_ylabel(r'P [W]' + suff)
     ax_rad_pow.get_yaxis().get_major_formatter().set_useOffset(False)
     ax_rad_pow.get_yaxis().get_major_formatter().set_scientific(True)
-    if np.amax(g.p_int) > 0 and log:
+    if np.amax(power) > 0 and log:
         ax_rad_pow.set_yscale('log')
     if not log:
         ax_rad_pow.set_ylim(ymin=0)
@@ -1198,17 +1238,17 @@ def subfig_evo_rad_pow_en(ax_rad_pow, g, legend, log=1, **kwargs):
     ax_rad_en = ax_rad_pow.twinx()
     ax_rad_en.get_yaxis().get_major_formatter().set_useOffset(False)
     ax_rad_en.get_yaxis().get_major_formatter().set_scientific(True)
-    if np.amax(g.p_int) > 0 and log:
-        ax_rad_en.plot(g.z, g.pulse_energy, 'k--', linewidth=1.5)
-        ax_rad_en.set_ylabel(r'E [J]')
+    if np.amax(power) > 0 and log:
+        ax_rad_en.plot(g.z, energy, 'k--', linewidth=1.5)
+        ax_rad_en.set_ylabel(r'E [J]' + suff)
         ax_rad_en.set_yscale('log')
     if not log:
-        if np.amax(g.pulse_energy) < 1e-4:
-            ax_rad_en.plot(g.z, g.pulse_energy * 1e6, 'k--', linewidth=1.5)
-            ax_rad_en.set_ylabel(r'E [$\mu$J]')
+        if np.amax(energy) < 1e-4:
+            ax_rad_en.plot(g.z, energy * 1e6, 'k--', linewidth=1.5)
+            ax_rad_en.set_ylabel(r'E [$\mu$J]' + suff)
         else:
-            ax_rad_en.plot(g.z, g.pulse_energy * 1e3, 'k--', linewidth=1.5)
-            ax_rad_en.set_ylabel(r'E [mJ]')
+            ax_rad_en.plot(g.z, energy * 1e3, 'k--', linewidth=1.5)
+            ax_rad_en.set_ylabel(r'E [mJ]' + suff)
         ax_rad_en.set_ylim(ymin=0)
     plt.yticks(plt.yticks()[0][0:-1])
 
@@ -1224,8 +1264,8 @@ def subfig_evo_rad_pow_en(ax_rad_pow, g, legend, log=1, **kwargs):
     ax_rad_en.yaxis.get_offset_text().set_color(ax_rad_en.yaxis.label.get_color())
 
     if kwargs.get('showtext', True):
-        ax_rad_pow.text(0.98, 0.02, r'$P_{end}$= %.2e W ' '\n' r'$E_{end}$= %.2e J' % (np.amax(g.p_int[:, -1]),
-                                                                                       np.mean(g.p_int[:, -1],
+        ax_rad_pow.text(0.98, 0.02, r'$P_{end}$= %.2e W ' '\n' r'$E_{end}$= %.2e J' % (np.amax(power[:, -1]),
+                                                                                       np.mean(power[:, -1],
                                                                                                axis=0) * g(
                                                                                            'xlamds') * g(
                                                                                            'zsep') * g.nSlices / speed_of_light),
@@ -1234,12 +1274,22 @@ def subfig_evo_rad_pow_en(ax_rad_pow, g, legend, log=1, **kwargs):
 
 
 @if_plottable
-def subfig_evo_rad_pow(ax_rad_pow, g, legend, log=1, **kwargs):
-    ax_rad_pow.plot(g.z, np.amax(g.p_int, axis=0), 'g-', linewidth=1.5)
-    ax_rad_pow.set_ylabel('P [W]')
+def subfig_evo_rad_pow(ax_rad_pow, g, legend, log=1, harm=1, **kwargs):
+    if harm == 1:
+        power = g.p_int
+        suff = ''
+    else:
+        try:
+            power = getattr(g, 'h{}_power'.format(harm))
+            suff = '  (harm {})'.format(harm)
+        except:
+            power = np.zeros_like(g.p_int)
+            suff = ''
+    ax_rad_pow.plot(g.z, np.amax(power, axis=0), 'g-', linewidth=1.5)
+    ax_rad_pow.set_ylabel('P [W]' + suff)
     ax_rad_pow.get_yaxis().get_major_formatter().set_useOffset(False)
     ax_rad_pow.get_yaxis().get_major_formatter().set_scientific(True)
-    if np.amax(g.p_int) > 0 and log:
+    if np.amax(power) > 0 and log:
         ax_rad_pow.set_yscale('log')
     plt.yticks(plt.yticks()[0][0:-1])
 
@@ -1248,7 +1298,7 @@ def subfig_evo_rad_pow(ax_rad_pow, g, legend, log=1, **kwargs):
     ax_rad_pow.yaxis.label.set_color('g')
     ax_rad_pow.yaxis.get_offset_text().set_color(ax_rad_pow.yaxis.label.get_color())
     if kwargs.get('showtext', True):
-        ax_rad_pow.text(0.98, 0.02, r'$P_{end}$= %.2e W' % (np.amax(g.p_int[:, -1])), fontsize=12,
+        ax_rad_pow.text(0.98, 0.02, r'$P_{end}$= %.2e W' % (np.amax(power[:, -1])), fontsize=12,
                         horizontalalignment='right', verticalalignment='bottom', transform=ax_rad_pow.transAxes)
 
 
@@ -1398,7 +1448,7 @@ def subfig_rad_size(ax_size_t, g, legend, **kwargs):
 @if_plottable
 def subfig_evo_rad_pow_sz(ax_power_evo, g, legend, norm=1, **kwargs):
     if g.nSlices > 1:
-
+        
         y_units = kwargs.get('subfig_evo_rad_pow_sz_yunits', 'um')
         dgrid = kwargs.get('subfig_evo_rad_pow_sz_dgrid', True)
         z = g.z
@@ -1418,7 +1468,6 @@ def subfig_evo_rad_pow_sz(ax_power_evo, g, legend, norm=1, **kwargs):
         ax_power_evo.set_xlabel('z [m]')
         ax_power_evo.set_ylabel(y_label)
         ax_power_evo.axis('tight')
-
         ax_power_evo.grid(dgrid)
     else:
         pass
@@ -1428,13 +1477,12 @@ def subfig_evo_rad_pow_sz(ax_power_evo, g, legend, norm=1, **kwargs):
 def subfig_evo_rad_spec_sz(ax_spectrum_evo, g, legend, norm=1, **kwargs):
     if not hasattr(g, 'spec'):
         g.calc_spec()
-
+        
     if g.nSlices > 1:
         z = g.z
-
+        
         y_units = kwargs.get('subfig_evo_rad_spec_sz_yunits', 'ev')
         dgrid = kwargs.get('subfig_evo_rad_spec_sz_dgrid', True)
-
         if y_units in ['ev', 'eV', 'phen']:
             l = g.freq_ev
             y_label = '$E_{photon}$ [eV]'
@@ -1458,7 +1506,7 @@ def subfig_evo_rad_spec_sz(ax_spectrum_evo, g, legend, norm=1, **kwargs):
 
 @if_plottable
 def plot_gen_out_scanned_z(g, figsize=(10, 14), legend=True, fig_name=None, z=inf, savefig=False):
-    if g('itdp') is True:
+    if g('itdp') == True:
         print('    plotting scan at ' + str(z) + ' [m]')
         print('!     Not implemented yet for time dependent, skipping')
         return
@@ -1941,7 +1989,7 @@ def plot_gen_stat(proj_dir, run_inp=[], stage_inp=[], param_inp=[],
 
                         plt.ylabel(dict_name.get(param, param) + '  ' + dict_unit.get(param, '') + ' (' + str(
                             s_ind) + ' um, ' + str(z_ind) + ' m)')
-                        if savefig is not False:
+                        if savefig != False:
                             if debug > 1:
                                 print('      saving ' + run_fig_name + '.' + savefig)
                             plt.draw()
@@ -2113,10 +2161,10 @@ def plot_gen_corr(proj_dir, run_inp=[], p1=(), p2=(), savefig=False, showfig=Tru
     saving_path = proj_dir + 'results/'
 
     plt.draw()
-    if savefig is not False:
+    if savefig != False:
         print('      saving ' + corr_fig_name + '.' + savefig)
         plt.savefig(saving_path + corr_fig_name + '.' + savefig, format=savefig)
-    if saveval is not False:
+    if saveval != False:
         print('      saving ' + corr_fig_name + '.txt')
         np.savetxt(saving_path + corr_fig_name + '.txt', np.vstack([var_1, var_2]).T, fmt="%E", newline='\n',
                    comments=param_1 + '_s' + str(stage_1) + '_at' + str(z_1) + '_' + str(
@@ -2133,7 +2181,7 @@ def plot_gen_corr(proj_dir, run_inp=[], p1=(), p2=(), savefig=False, showfig=Tru
 def plot_dpa_bucket_out(out, dpa=None, slice_pos='max_I', repeat=1, GeV=1, figsize=4, cmap=def_cmap, scatter=True,
                         energy_mean=None, legend=True, fig_name=None, savefig=False, showfig=True, bins=[50, 50],
                         debug=1):
-    if dpa is None:
+    if dpa == None:
         dpa = read_dpa_file_out(out)
 
     if out.nSlices > 1:
@@ -2166,118 +2214,126 @@ def plot_dpa_bucket_out(out, dpa=None, slice_pos='max_I', repeat=1, GeV=1, figsi
 def plot_dpa_bucket(dpa, slice_num=None, repeat=1, GeV=1, figsize=4, cmap=def_cmap, scatter=False, energy_mean=None,
                     legend=True, fig_name=None, savefig=False, showfig=True, suffix='', bins=(50, 50), debug=1,
                     return_mode_gamma=0):
-    part_colors = ['darkred', 'orange', 'g', 'b', 'm', 'c', 'y']
+    part_colors = ['darkred', 'orange', 'g', 'b', 'm', 'c', 'y', 'olive']
     # cmap='BuPu'
     y_bins = bins[0]
     z_bins = bins[1]
-
+    
     if showfig == False and savefig == False:
         return
-
+    
     _logger.info('plotting dpa bucket')
     start_time = time.time()
-
+    
     # if dpa.__class__ != GenesisParticlesDump:
     #     raise ValueError('wrong particle object: should be GenesisParticlesDump')
-
+    
     if np.shape(dpa.ph)[0] == 1:
         slice_num = 0
-    if slice_num is None:
+    if slice_num == None:
         slice_num = int(np.shape(dpa.ph)[0] / 2)
         _logger.debug(
             ind_str + 'no slice number provided, using middle of the distribution - slice number {}'.format(slice_num))
     else:
         assert (slice_num <= np.shape(dpa.ph)[0]), 'slice_num larger than the dpa shape'
-
-    if fig_name is None:
+    
+    if fig_name == None:
         fig_name = 'Electron phase space ' + dpa.fileName()
     fig = plt.figure(fig_name)
     fig.clf()
     fig.set_size_inches((5 * figsize, 3 * figsize), forward=True)
-
+    
     left, width = 0.18, 0.57
     bottom, height = 0.14, 0.55
     left_h = left + width + 0.02 - 0.02
     bottom_h = bottom + height + 0.02 - 0.02
-
+    
     rect_scatter = [left, bottom, width, height]
     rect_histx = [left, bottom_h, width, 0.2]
     rect_histy = [left_h, bottom, 0.15, height]
-
+    
     ax_main = plt.axes(rect_scatter)
     ax_z_hist = plt.axes(rect_histx, sharex=ax_main)
     ax_y_hist = plt.axes(rect_histy, sharey=ax_main)
-
+    
     # ax_z_hist = plt.subplot2grid((4, 1), (0, 0), rowspan=1)
     # ax_y_hist = plt.subplot2grid((4, 1), (0, 0), rowspan=1)
-
+    
     # ax_main = plt.subplot2grid((4, 1), (1, 0), rowspan=3, sharex=ax_z_hist)
-
+    
     nbins = np.shape(dpa.ph)[1]
     phase = deepcopy(dpa.ph[slice_num, :, :])
     energy = deepcopy(dpa.e[slice_num, :, :])
     _logger.debug(ind_str + 'nbins =  {}'.format(nbins))
-
+    
+    # checking for lost particles
+    if np.any(energy<0):
+        particle_present_idx = energy>0
+        energy = energy[particle_present_idx]
+        phase = phase[particle_present_idx]
+    
     if GeV:
         energy *= m_e_MeV
-        if energy_mean is None:
+        if energy_mean == None:
             energy_mean = round(np.mean(energy), 0)
     else:
-        if energy_mean is None:
+        if energy_mean == None:
             energy_mean = round(np.mean(energy), 1)
     energy -= energy_mean
-
+    
     phase_flat = phase.flatten()
     energy_flat = energy.flatten()
     for irep in range(repeat - 1):
         phase_flat = np.append(phase_flat, phase.flatten() + 2 * np.pi * (irep + 1))
         energy_flat = np.append(energy_flat, energy.flatten())
-
+    
     # phase_hist = np.ravel(phase)
     # for irep in range(repeat-1):
     #     phase_hist = np.concatenate((phase_hist, np.ravel(phase) + 2 * np.pi * (irep+1)))
-
+    
     # hist, edges = np.histogram(phase_hist, bins=50 * repeat)  # calculate current histogram
     hist_z, edges_z = np.histogram(phase_flat, bins=z_bins * repeat)  # calculate current histogram
     edges_z = edges_z[0:-1]  # remove the last bin edge to save equal number of points
     ax_z_hist.bar(edges_z, hist_z, width=edges_z[1] - edges_z[0], color='silver')
     ax_z_hist.set_ylabel('counts')
-
-    hist_y, edges_y = np.histogram(energy_flat, bins=y_bins)  # calculate current histogram
+    
+    hist_y, edges_y = np.histogram(energy_flat, bins=y_bins)  # calculate energy histogram
     edges_y = edges_y[0:-1]  # remove the last bin edge to save equal number of points
     ax_y_hist.barh(edges_y, hist_y, height=edges_y[1] - edges_y[0], color='silver')
     ax_y_hist.set_xlabel('counts')
-
+    
     for label in ax_z_hist.get_xticklabels():
         label.set_visible(False)
-
+    
     for label in ax_y_hist.get_yticklabels():
         label.set_visible(False)
-
-    if scatter is True:
+    
+    if scatter == True:
+        _logger.debug(ind_str + 'plotting scatter')
         for irep in range(repeat):
             for ibin in range(nbins):
                 ax_main.scatter(phase[ibin, :] + 2 * np.pi * (irep), energy[ibin, :], color=part_colors[ibin],
                                 marker='.')
-
+    
         # ax_z_hist.set_xlim([edges[0], edges[-1]])
-
-    elif scatter is False:
+    
+    elif scatter == False:
+        _logger.debug(ind_str + 'plotting colormesh')
         ax_main.hist2d(phase_flat, energy_flat, bins=[z_bins * repeat, y_bins], cmin=0, cmap=cmap)
-
+    
     ax_main.set_xlabel('$\phi$ [rad]')
     if GeV:
         ax_main.set_ylabel('E [MeV] + ' + str(energy_mean / 1000) + ' [GeV]')
     else:
         ax_main.set_ylabel('$\gamma$ + ' + str(energy_mean))
-
+    
     plt.draw()
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         _logger.debug(ind_str + 'saving to {}'.format(dpa.fileName() + suffix + '.' + savefig))
         plt.savefig(dpa.filePath + suffix + '.' + savefig, format=savefig)
-
+    
     if showfig:
         rcParams["savefig.directory"] = os.path.dirname(dpa.filePath)
         plt.show()
@@ -2290,7 +2346,7 @@ def plot_dpa_bucket(dpa, slice_num=None, repeat=1, GeV=1, figsize=4, cmap=def_cm
 def plot_edist(edist, figsize=4, fig_name=None, savefig=False, showfig=True, scatter=False, plot_x_y=True,
                plot_xy_s=True, bins=(50, 50, 50, 50), flip_t=False, x_units='um', y_units='ev', cmin=0, y_offset=None,
                cmap=def_cmap, debug=1):
-    if showfig is False and savefig is False:
+    if showfig == False and savefig == False:
         return
     _logger.info('plotting edist file')
     start_time = time.time()
@@ -2301,7 +2357,7 @@ def plot_edist(edist, figsize=4, fig_name=None, savefig=False, showfig=True, sca
     if np.size(bins) == 1:
         bins = (bins, bins, bins, bins)  # x,y,t,e
 
-    if fig_name is None:
+    if fig_name == None:
         fig_name = 'Electron distribution ' + edist.fileName()
     fig = plt.figure(fig_name)
     fig.clf()
@@ -2336,7 +2392,7 @@ def plot_edist(edist, figsize=4, fig_name=None, savefig=False, showfig=True, sca
     else:  # elif beam_E_plot=='gamma':
         energy = edist.g
 
-    if y_offset is None:
+    if y_offset == None:
         y_offset = int(np.mean(energy))
     if scatter:
         ax_se.scatter(s, energy - y_offset, marker='.')
@@ -2394,10 +2450,10 @@ def plot_edist(edist, figsize=4, fig_name=None, savefig=False, showfig=True, sca
     fig.subplots_adjust(wspace=0.4, hspace=0.4)
 
     plt.draw()
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
-        if savefig in ['png', 'eps', 'pdf', 'jpeg']:
+        if savefig in ['png' , 'eps', 'pdf', 'jpeg']:
             savepath = edist.filePath + '.' + savefig
         else:
             savepath = savefig
@@ -2415,6 +2471,8 @@ def plot_edist(edist, figsize=4, fig_name=None, savefig=False, showfig=True, sca
     # return fig
 
 
+
+
 """
 tmp for HXRSS
 """
@@ -2488,8 +2546,8 @@ def read_plot_dump_proj(exp_dir, stage, run_ids, plot_phase=1, showfig=True, sav
 
     plt.draw()
 
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         if debug > 1:
             print('      saving ' + fig_name + '.' + savefig)
@@ -2525,8 +2583,8 @@ def read_plot_dump_proj(exp_dir, stage, run_ids, plot_phase=1, showfig=True, sav
 
     plt.draw()
 
-    if savefig is not False:
-        if savefig is True:
+    if savefig != False:
+        if savefig == True:
             savefig = 'png'
         if debug > 1:
             print('      saving ' + fig_name + '.' + savefig)
diff --git a/ocelot/gui/settings_plot.py b/ocelot/gui/settings_plot.py
index da6af06f..746f0a45 100644
--- a/ocelot/gui/settings_plot.py
+++ b/ocelot/gui/settings_plot.py
@@ -4,27 +4,52 @@
 # from pylab import rc, rcParams #tmp
 from matplotlib import rc, rcParams
 from mpl_toolkits.axes_grid1 import make_axes_locatable
-from copy import deepcopy
+from copy import copy, deepcopy
 from ocelot.common.ocelog import ind_str
+from matplotlib.colors import LinearSegmentedColormap
 
 #in order to run decorators properly
 import functools
 
 _logger = logging.getLogger(__name__)
 
-my_viridis = deepcopy(matplotlib.pyplot.get_cmap('viridis')) 
+# my_viridis = deepcopy(matplotlib.pyplot.get_cmap('viridis')) 
+my_viridis = copy(matplotlib.cm.get_cmap("viridis"))
 my_viridis.set_under('w')
 def_cmap = my_viridis
 
+#serval colormap (diverging
+colors = [(181/256, 101/256, 29/256), (250/256, 228/256, 170/256), (7/256, 0/256, 14/256)]  # R -> G -> B
+cmap_name = 'serval'
+cmap_serval = matplotlib.colors.LinearSegmentedColormap.from_list(cmap_name, colors, N=256)
+
+#ocelot colormap
+colors = [(255/256, 213/256, 199/256),  (181/256, 101/256, 29/256), (7/256, 0/256, 14/256)]  # R -> G -> B
+cmap_name = 'ocelot'
+cmap_ocelot = matplotlib.colors.LinearSegmentedColormap.from_list(cmap_name, colors, N=256)
+
+
 def_cmap = 'viridis'
 # def_cmap = 'Greys'
 
 fntsz = 4
-params = {'image.cmap': def_cmap, 'backend': 'ps', 'axes.labelsize': 3 * fntsz, 'font.size': 3 * fntsz, 'legend.fontsize': 4 * fntsz, 'xtick.labelsize': 4 * fntsz,  'ytick.labelsize': 4 * fntsz, 'text.usetex': False}
+params = {'image.cmap': def_cmap, 'axes.labelsize': 3 * fntsz, 'font.size': 3 * fntsz, 'legend.fontsize': 4 * fntsz, 'xtick.labelsize': 4 * fntsz,  'ytick.labelsize': 4 * fntsz, 'text.usetex': False}
 rcParams.update(params)
+
+
+# import packaging
+# matplotlib_version = packaging.version.parse(matplotlib.__version__).major
+
+if int(matplotlib.__version__.split('.')[0]) < 3:
+    try:    
+        rcParams.update({'pcolor.shading':'nearest'})
+    except KeyError:
+        _logger.debug('matplotlib too old for "pcolor.shading":"nearest" setting')
+
+
 # plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)
 # rcParams["savefig.directory"] = os.chdir(os.path.dirname(__file__)) but __file__ appears to be genesis_plot
-matplotlib.pyplot.ioff() #turn off interactive mode
+# matplotlib.pyplot.ioff() #turn off interactive mode
 
 #matplotlib.pyplot.style.use("dark_background") White axes on dark background
 # matplotlib.use('Agg')
@@ -46,11 +71,11 @@
 #    _logger.error(plotting_error)
 
 # # re-check
-# exitval = os.system('python -c "import matplotlib.pyplot as plt; plt.figure()"')
+# exitval = os.system('python -c "import matplotlib.pyplot as plt; plt.figure()"')exit
 # havedisplay = (exitval == 0)
 # if not havedisplay:
 # # force matplotlib not ot use Xwindows backend. plots may still be plotted into e.g. *.png
-# matplotlib.use('Agg')
+# matplotlib.use('TkAgg') #fix for matplotlib version 
 
 
 #decorator
diff --git a/ocelot/optics/bragg.py b/ocelot/optics/bragg.py
index 1936c4ff..890ce69e 100644
--- a/ocelot/optics/bragg.py
+++ b/ocelot/optics/bragg.py
@@ -27,6 +27,8 @@
 
 r_el        = 2.8179403267e-15       #Electron classical radius in:  m
 
+_indexing_reversed = True
+
 def calc_angle(a,b):
     '''
     yields angle between vectors "a"=(ax,ay,az) and "b"=(bx,by,bz) in degrees
@@ -153,7 +155,10 @@ def F_hkl(cryst, ref_idx, lamb, temp):
     
     _logger.debug('calculating Fhkl {} {} {}'.format(lamb, cryst.lattice.element_name, ref_idx))
     
-    file_name = cryst.lattice.element_name + str(ref_idx[2]) + str(ref_idx[1]) + str(ref_idx[0]) + '.dat'
+    if _indexing_reversed:
+        file_name = cryst.lattice.element_name + str(ref_idx[0]) + str(ref_idx[1]) + str(ref_idx[2]) + '.dat'
+    else:
+        file_name = cryst.lattice.element_name + str(ref_idx[2]) + str(ref_idx[1]) + str(ref_idx[0]) + '.dat'
     
     target_ev = 2*pi * hbar * c / lamb
     
@@ -195,7 +200,7 @@ def find_bragg(lambd, lattice, ord_max):
     H = {}
     d = {}
     phi = {}
-    
+   
     for h in range(0, ord_max+1):
         for k in range(0, ord_max+1):
             for l in range(0, ord_max+1):
@@ -204,6 +209,7 @@ def find_bragg(lambd, lattice, ord_max):
                     continue
                             
                 hkl = (h,k,l)
+                
     
                 H_hkl = h*lattice.b1 + k*lattice.b2 + l*lattice.b3
                 d_hkl = 1. / np.linalg.norm(H_hkl)
@@ -213,8 +219,7 @@ def find_bragg(lambd, lattice, ord_max):
                 if np.abs(sin_phi) <= 1.0:
                     H[hkl] = H_hkl
                     d[hkl] = d_hkl
-                    phi[hkl] = np.arcsin(sin_phi) * 180.0 / np.pi
-
+                    phi[hkl] = np.arcsin(sin_phi) * 180.0 / np.pi                
     return H, d, phi
    
 
@@ -392,6 +397,213 @@ def transmissivity_reflectivity(klist, cryst):
     return t, r
 
 
+##########################################################
+    
+def rotm(th,ux,uy,uz):
+    r = np.array((
+            ( ux*ux*(1-np.cos(th))+np.cos(th),     ux*uy*(1-np.cos(th))-uz*np.sin(th),     ux*uz*(1-np.cos(th))+uy*np.sin(th) ),
+            ( ux*uy*(1-np.cos(th))+uz*np.sin(th),  uy*uy*(1-np.cos(th))+np.cos(th),        uy*uz*(1-np.cos(th))-ux*np.sin(th) ),
+            ( ux*uz*(1-np.cos(th))-uy*np.sin(th),  uy*uz*(1-np.cos(th))+ux*np.sin(th),     uz*uz*(1-np.cos(th))+np.cos(th)    )
+            ))
+    return r
+
+
+#(1) Pitch of thp around PitchAx, and rotation of Yaw and Roll axis:
+def rotm1(thp,pitchax,rollax,yawax):       
+    r1 = rotm(np.pi/2-thp,pitchax[0],pitchax[1],pitchax[2])
+    #print('==========================')
+    #print('matrix',r1)
+    #print('rollax',rollax)
+    #print('==========================')
+    rollax2 = r1.dot(rollax)
+    yawax2  = r1.dot(yawax)
+    return r1, rollax2, yawax2
+
+#(2) Yaw of thy around yawax2, and rotation of Roll axis:
+def rotm2(thy,rollax2,yawax2):    
+    r2 = rotm(thy,yawax2[0],yawax2[1],yawax2[2])
+    rollax3 = r2.dot(rollax2)    
+    return r2, rollax3
+
+#(3) Roll of thr around Rollax3:
+def rotm3(thr,rollax3):    
+    r3 = rotm(thr,rollax3[0],rollax3[1],rollax3[2])
+    return r3
+
+
+
+def my_get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
+    from scipy.optimize import fsolve 
+    from scipy import optimize
+    _logger.debug('==============================================')
+    _logger.debug('======== BEGIN getting crystal filter ========')
+    _logger.debug('==============================================')    
+    #import crystal as cry    
+    #n_width - number of Darwin widths
+    lamb=h_eV_s*speed_of_light/ev_seed
+    kb = 2*np.pi/lamb
+    
+    ref_idx=cryst.ref_idx
+    no = cryst.no/np.linalg.norm(cryst.no)
+    yawax = no
+    rollax = cryst.cut/np.linalg.norm(cryst.cut)
+    
+    
+    
+    #finds pitch from roll and yaw 
+    pitchax = -np.cross(yawax,rollax)/np.linalg.norm(np.cross(yawax,rollax))
+    _logger.debug(ind_str + 'reflection index = {}'.format(ref_idx))            
+    _logger.debug(ind_str + 'x = pitch axis = {}'.format(pitchax))
+    _logger.debug(ind_str + 'z = yaw axis   = {}'.format(yawax))
+    _logger.debug(ind_str + 'y = roll axis  = {}'.format(rollax))
+    H, d, phi = find_bragg(lambd = lamb, lattice=cryst.lattice, ord_max = 15)    
+    polarization = 'sigma'
+    abs_ref_idx = tuple(abs(np.array(ref_idx)))
+    dhkl = d[abs_ref_idx]
+        
+    #solves for bragg angle
+    thetaB = phi[abs_ref_idx]* np.pi / 180.0
+    _logger.debug(ind_str + 'Bragg angle {} [rad]'.format(thetaB))
+    _logger.debug(ind_str + 'Bragg angle {} [deg]'.format(thetaB/np.pi*180))
+    
+
+    #Finding the incident vector wrt crystal system coordinates
+    
+    
+    
+    if polarization == 'sigma':
+        c_pol = 1
+    else :
+        c_pol = - np.cos(2.0 * thetaB)
+    
+    ref_idx_length = np.sqrt(np.sum(np.array(ref_idx)**2))
+    h_norm = tuple([i/ref_idx_length for i in ref_idx])
+  
+    #1) Perform pitch rotation of initial incient axis (0,0,1), and finds theta_pitch 
+    #   In principle one could yaw and roll as well. But for our applications this is not interesting
+    #   Yaw and roll angles are set to zero
+    #print('thetaB',thetaB*180/np.pi)
+    def func(thetap):
+        #print('thetap',thetap*180/np.pi)
+        thp=float(thetap)        
+        return np.sin(thetaB)-np.dot(h_norm,np.dot(rotm1(thp,pitchax,rollax,yawax)[0],np.array([0,0,1])))
+    #print('funzione',func(np.pi/4))
+    
+    thetap=float(fsolve(func,thetaB))
+    if thetap>np.pi:
+        thetap=thetap-np.pi
+    _logger.debug(ind_str + 'Pitch angle {} [rad]'.format(thetap))
+    _logger.debug(ind_str + 'Pitch angle {} [deg]'.format(thetap*180/np.pi))
+    
+    s0 = np.dot(rotm1(thetap,pitchax,rollax,yawax)[0],np.array([0,0,1]))
+    #print('s0',s0,'|s0|',np.linalg.norm(s0))
+    #print(s0,2*np.dot(s0,h_norm),np.array(h_norm))
+    #print('sh=',s0-2*np.dot(s0,h_norm)*np.array(h_norm),np.linalg.norm(s0-2*np.dot(s0,h_norm)*np.array(h_norm)))
+    
+    #def eqs(sh):
+    #    return np.dot(s0,h_norm)-np.dot(sh,h_norm), np.dot(s0,np.cross(sh,h_norm)), np.linalg.norm(sh)-1
+       
+    #sh = fsolve(eqs,(0,0,0))
+    
+    #print(sh)
+    #print(np.dot(s0,h_norm)-np.dot(sh,h_norm), np.dot(s0,np.cross(sh,h_norm)), np.linalg.norm(sh)-1)
+    sh = (s0-2*np.dot(s0,h_norm)*np.array(h_norm))/np.linalg.norm(s0-2*np.dot(s0,h_norm)*np.array(h_norm))
+    
+    print(s0,sh,no)
+   
+    gamma0 = np.dot(no, s0)
+    gammah = np.dot(no, sh)
+    
+    psi0 = np.arccos(gamma0)
+    psih = np.arccos(gammah)
+    psin = psih - thetaB 
+    
+    _logger.debug(ind_str + 'no   = {}'.format(no))
+    _logger.debug(ind_str + 's0 = {}'.format(s0))
+    _logger.debug(ind_str + 'h_norm  = {}'.format(h_norm))
+    _logger.debug(ind_str + 'sh  = {}'.format(sh))
+    _logger.debug(ind_str + 'psi0 [deg]= {}'.format(psi0*180/np.pi))
+    _logger.debug(ind_str + 'psih [deg]= {}'.format(psih*180/np.pi))
+    _logger.debug(ind_str + 'psin [deg] = {}'.format(psin*180/np.pi))
+    
+    
+   
+    
+    
+    gamma = gammah / gamma0
+
+    _logger.debug(ind_str + '2 theta = {} deg'.format(calc_angle(s0,-sh)))
+    _logger.debug(ind_str + 'gamma0: {}'.format(gamma0))
+    _logger.debug(ind_str + 'gammah: {}'.format(gammah))
+    _logger.debug(ind_str + 'gamma: {}'.format(gamma))
+    if gamma<0:
+        _logger.debug(2*ind_str + 'BRAGG geometry')
+    else:
+        _logger.warning(2*ind_str + 'LAUE geometry')
+
+
+    #cahnged by GG: abs_ref_idx to ref_idx
+    f0, fh, fmh =  F_hkl(cryst = cryst, ref_idx = ref_idx, lamb=lamb, temp = 300*K)
+    
+    
+#    _logger.debug(ind_str + 'structure factors {} {} {}'.format(f0, fh, fmh))
+    #plt.figure()
+
+     
+        
+    vcell = ( dhkl * np.sqrt( np.dot(ref_idx,ref_idx) ) ) **3
+        
+    delta    = r_el * np.abs(c_pol) * lamb**2 * np.sqrt( np.abs(gamma)*fh*fmh ) / ( np.pi * vcell * np.sin(2*thetaB) )
+    mid_TH = np.real( r_el * lamb**2 * f0 * (1-gamma) / (2*np.pi * vcell * np.sin(2*thetaB)) )
+    mid_k  = kb / (- mid_TH * 1/np.tan(thetaB) + 1 )
+    dk  =  ( -2*kb*np.sin(thetaB) + np.sqrt(16*mid_k**2 * np.real(delta)**2 * np.cos(thetaB)**2 + 4*kb**2 * np.sin(thetaB)**2) ) / ( 2 * np.real(delta) * np.cos(thetaB) )
+    
+    print('vcell', vcell)
+    print('mid_k', mid_k)
+    
+    ki, kf = mid_k - n_width*dk, mid_k + n_width*dk    #final   k    
+    
+    if k == None:    
+        k = np.linspace(ki, kf, nk)    
+        
+    
+    cryst.lamb = lamb
+    cryst.kb = kb
+    cryst.kb = 2 * kb - mid_k # bugfix
+    cryst.thetaB = thetaB
+    cryst.gamma = gamma
+    cryst.gamma0 = gamma0
+    cryst.gammah = gammah
+    cryst.c_pol = c_pol
+    cryst.chi0  = - ( r_el * lamb**2 * f0  ) / ( np.pi * vcell )
+    cryst.chih  = - ( r_el * lamb**2 * fh  ) / ( np.pi * vcell )
+    cryst.chimh = - ( r_el * lamb**2 * fmh ) / ( np.pi * vcell )
+    cryst.pl = np.pi * vcell * np.sqrt( gamma0 * np.abs(gammah) ) / ( r_el * lamb * np.abs(c_pol) * np.sqrt( fh*fmh ) )
+    
+    
+    from ocelot.optics.wave import TransferFunction #hotfix here
+    f = TransferFunction()
+    
+    f.tr, f.ref = transmissivity_reflectivity(k, cryst)   
+    
+    f.k = k
+    f.thetaB = thetaB
+    f.mid_k = mid_k
+    f.dk = dk
+    f.xlamds = lamb
+    f.cryst = cryst
+    
+    f.actual = f.tr - np.exp(-1j* cryst.chi0 * (cryst.kb*cryst.size[2]/(2*cryst.gamma0)))
+    f.const = np.exp(-1j* cryst.chi0 * (cryst.kb*cryst.size[2]/(2*cryst.gamma0)))
+    _logger.debug('=============================')
+    _logger.debug('======== END END END ========')
+    _logger.debug('=============================')
+    return f
+
+
+#########################################################
+
+
 def get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
     _logger.debug('getting crystal filter')
     #import crystal as cry
@@ -408,6 +620,10 @@ def get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
     polarization = 'sigma'
 
     abs_ref_idx = tuple(abs(np.array(ref_idx)))
+    #print(np.array(ref_idx))
+    #print(abs(np.array(ref_idx)))
+    #print(abs_ref_idx)
+    #print(d)
     dhkl = d[abs_ref_idx]
     
     '''
@@ -429,6 +645,7 @@ def get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
     ref_idx_length = np.sqrt(np.sum(np.array(ref_idx)**2))
     h_norm = tuple([i/ref_idx_length for i in ref_idx])
     h = np.array([i*2*np.pi/dhkl for i in h_norm]) # normalized q-vector of crystalline plane
+   
 
     #quadratic equation coefficients to find incidence angle
     a = - 0.5 * np.sin(thetaB)**2 + 0.5*h_norm[2]**2
@@ -495,8 +712,8 @@ def get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
         _logger.warning(2*ind_str + 'LAUE geometry')
 
 
-    
-    f0, fh, fmh =  F_hkl(cryst = cryst, ref_idx = abs_ref_idx, lamb=lamb, temp = 300*K)
+    #cahnged by GG: abs_ref_idx to ref_idx
+    f0, fh, fmh =  F_hkl(cryst = cryst, ref_idx = ref_idx, lamb=lamb, temp = 300*K)
     
     
 #    _logger.debug(ind_str + 'structure factors {} {} {}'.format(f0, fh, fmh))
@@ -569,4 +786,4 @@ def unfold_angles(Phlist):
 if __name__ == "__main__":
     plot_bragg_reflections()
     #plot_scattering_factors()
-    
\ No newline at end of file
+    
diff --git a/ocelot/optics/bragg_old.py b/ocelot/optics/bragg_old.py
new file mode 100644
index 00000000..1936c4ff
--- /dev/null
+++ b/ocelot/optics/bragg_old.py
@@ -0,0 +1,572 @@
+'''
+crystal optics
+'''
+
+from ocelot.optics.elements import Crystal
+from ocelot.optics.wave import *
+from ocelot.optics.ray import Ray, trace as trace_ray
+from ocelot.common.ocelog import *
+import logging
+_logger = logging.getLogger(__name__) 
+# from ocelot.gui.optics import *
+
+import numpy as np
+# from pylab import *
+import sys, os
+
+m = 1.0
+cm = 1.e-2
+mm = 1.e-3
+mum = 1.e-6
+nm = 1.e-9
+A = 1.e-10
+K = 1.0
+
+hbar = 6.58211928e-16
+c = 299792458.0 
+
+r_el        = 2.8179403267e-15       #Electron classical radius in:  m
+
+def calc_angle(a,b):
+    '''
+    yields angle between vectors "a"=(ax,ay,az) and "b"=(bx,by,bz) in degrees
+    '''
+    a_ = np.array(a)
+    b_ = np.array(b)
+    return np.arccos(np.dot(a_,b_)/np.linalg.norm(a_)/np.linalg.norm(b_)) / np.pi * 180
+
+'''
+element database
+'''
+class Element():
+    def __init__(self):
+        pass
+
+elements = {}
+
+elements['H'] = Element()
+elements['H'].Z = 1
+elements['H'].A = 1
+
+elements['C'] = Element()
+elements['C'].Z = 6
+elements['C'].A = 12
+
+lattice_unit_cells = {}
+cells = {}
+
+lattice_unit_cells['NaCl'] = (np.array([5.6404*A, 0, 0]), np.array([0, 5.6404*A, 0]), np.array([0, 0, 5.6404*A]))
+
+lattice_unit_cells['Si'] = (np.array([5.43*A, 0, 0]), np.array([0, 5.43*A, 0]), np.array([0, 0, 5.43*A]))
+#error?
+#cells['Si'] =(('C',[0,0,0]),('C',[0.5,0.5,0]),('C',[0.5,0,0.5]),('C',[0,0.5,0.5]),
+#              ('C',[0.25,0.25,0.25]),('C',[0.75,0.25,0.75]),('C',[0.25,0.75,0.75]),('C',[0.75,0.75,0.25])) 
+
+#diamond
+lattice_unit_cells['C'] = (np.array([3.567*A, 0, 0]), np.array([0, 3.567*A, 0]), np.array([0, 0, 3.567*A]))
+cells['C'] =(('C',[0,0,0]),('C',[0.5,0.5,0]),('C',[0.5,0,0.5]),('C',[0,0.5,0.5]),
+                     ('C',[0.25,0.25,0.25]),('C',[0.75,0.25,0.75]),('C',[0.25,0.75,0.75]),('C',[0.75,0.75,0.25]))
+
+lattice_unit_cells['Ge'] = (np.array([5.658*A, 0, 0]), np.array([0, 5.658*A, 0]), np.array([0, 0, 5.658*A]))
+                     
+class CrystalLattice():
+    def __init__(self, element_name):
+        self.element_name = element_name
+        self.a1 = lattice_unit_cells[element_name][0]
+        self.a2 = lattice_unit_cells[element_name][1]
+        self.a3 = lattice_unit_cells[element_name][2]
+        b_  = np.dot(self.a1, np.cross(self.a2, self.a3))
+        self.b1 = np.cross(self.a2, self.a3) / b_
+        self.b2 = np.cross(self.a3, self.a1) / b_
+        self.b3 = np.cross(self.a1, self.a2) / b_
+
+class CrystalCell():
+    def __init__(self, element_name):
+        pass
+
+g1 = Crystal(r=[0,0,0*cm], size=[13*cm,20*cm,10*cm], no=[0,0,-1], id='cr1')
+g1.lattice =  CrystalLattice('C')
+g1.temp = 100 * K
+
+
+s0 = [0,0,1] # beam direction
+
+class StructureFactorFactory():
+    def __init__(self):
+        pass
+
+    def atomic_structure_factor(self, element, model='spherical_elastic'):
+        if model == 'spherical_elastic':
+            return self.f_sperical_elastic(element)
+        else: return None
+
+    def f_spher(self, a, k):
+        '''
+        atomic scattering factor for hydrogen-like charge density of radius a
+        k is the momentum transfer sin(theta)/lambda
+        '''
+        return 1. / (1. + (2.*pi*a*k)**2)**2
+
+    def f_sperical_elastic(self, element):
+        if element == 'Li': ak = 12.0
+        else: ak = 13.0
+        def f(k):
+            return ak*k
+        return f
+
+
+'''
+atomic scattering factor
+'''
+def f_scat(phi, lambd):
+    '''
+    atomic scattering factor
+    '''
+    pass
+
+class CrystalStructureFactors():
+    def __init__(self):
+        pass
+
+def load_stucture_factors(file_name):
+    _logger.debug('loading structure factors {}'.format(file_name))   
+    import pickle
+    #sys.modules[]
+    #print ('im in module', __name__)
+    #print ('file ', sys.modules[__name__].__file__)
+    dir_name = os.path.dirname(sys.modules[__name__].__file__)
+    #print 'dir ', dir_name 
+    abs_file_name = os.path.join(dir_name, 'data', file_name)
+    _logger.debug(ind_str + 'full path {}'.format(abs_file_name))   
+#    print ('abs path ', abs_file_name)
+    cdata = pickle.load(open(abs_file_name, 'rb'))
+    return cdata
+
+def save_stucture_factors(cdata, file_name):
+    import pickle
+    print ('saving structure factors to', file_name)
+    # pickle.dump(cdata, open(file_name, 'wb')) #original
+    pickle.dump(cdata, open(file_name, 'wb'), pickle.HIGHEST_PROTOCOL) # fix for "No module named 'ocelot.optics.bragg\r'" error in Windows
+
+
+def F_hkl(cryst, ref_idx, lamb, temp):
+    
+    _logger.debug('calculating Fhkl {} {} {}'.format(lamb, cryst.lattice.element_name, ref_idx))
+    
+    file_name = cryst.lattice.element_name + str(ref_idx[2]) + str(ref_idx[1]) + str(ref_idx[0]) + '.dat'
+    
+    target_ev = 2*pi * hbar * c / lamb
+    
+    #print ('reading file_name', file_name)
+    #_logger.debug(ind_str + 'loading structure factors from {}'.format(file_name))    
+#    cdata = load_stucture_factors(file_name)
+    
+    try:
+        cdata = load_stucture_factors(file_name)
+    except:
+#        print ('form factor data not found!!!')
+        _logger.error(ind_str + 'form factor data not found')
+        sys.exit(0)
+        return 0.0, 0.0, 0.0
+    
+#    print ('searching ', target_ev)
+    _logger.debug(ind_str + 'searching Bragg condition for photon energy {} eV'.format(target_ev))
+    
+    if target_ev < cdata.ev[0] or target_ev > cdata.ev[-1]:
+        _logger.error(2*ind_str + 'photon wavelength not covered in data (target_ev > cdata.ev)')
+#        print ('photon wavelength not covered in data')
+        return 0.0, 0.0, 0.0
+        
+    de = cdata.ev[1] - cdata.ev[0]
+    i_e = int( (target_ev - cdata.ev[0]) / de )
+
+    # return cdata.f000[i_e], cdata.fh[i_e], cdata.fhbar[i_e]
+    f000 = np.interp(target_ev, cdata.ev, np.real(cdata.f000)) + 1j * np.interp(target_ev, cdata.ev, np.imag(cdata.f000))
+    fh = np.interp(target_ev, cdata.ev, np.real(cdata.fh)) + 1j * np.interp(target_ev, cdata.ev, np.imag(cdata.fh))
+    fhbar = np.interp(target_ev, cdata.ev, np.real(cdata.fhbar)) + 1j * np.interp(target_ev, cdata.ev, np.imag(cdata.fhbar))
+    _logger.debug(ind_str + 'f000 {}'.format(f000))
+    _logger.debug(ind_str + 'fh {}'.format(fh))
+    _logger.debug(ind_str + 'hbar {}'.format(fhbar))
+    return f000, fh, fhbar
+
+
+
+def find_bragg(lambd, lattice, ord_max):
+    H = {}
+    d = {}
+    phi = {}
+    
+    for h in range(0, ord_max+1):
+        for k in range(0, ord_max+1):
+            for l in range(0, ord_max+1):
+                
+                if h == k == l == 0:
+                    continue
+                            
+                hkl = (h,k,l)
+    
+                H_hkl = h*lattice.b1 + k*lattice.b2 + l*lattice.b3
+                d_hkl = 1. / np.linalg.norm(H_hkl)
+                                        
+                sin_phi = lambd / (2. * d_hkl)
+                
+                if np.abs(sin_phi) <= 1.0:
+                    H[hkl] = H_hkl
+                    d[hkl] = d_hkl
+                    phi[hkl] = np.arcsin(sin_phi) * 180.0 / np.pi
+
+    return H, d, phi
+   
+
+   
+def plot_bragg_reflections(idc = [(0,0,1), (1,1,1), (2,1,1), (3,1,1), (1,2,3), (4,0,0)]):
+    HH = {}
+    import matplotlib.pyplot as plt
+    lambds = np.linspace(0.5e-10 * m, 1.3e-9 * m, 50)
+    
+    for lambd in lambds:
+        H, d, phi = find_bragg(lambd = lambd, lattice=g1.lattice, ord_max = 5)
+        HH[lambd] = (H, d, phi) 
+    
+    plt.figure()
+    plt.grid()
+    lines = []; labels=[]
+    
+    for idx in idc:
+        y = []
+        lambds = []
+        
+        for l in HH.keys(): #sort(HH.keys()):
+            try:    
+                y.append(HH[l][2][idx])
+                lambds.append(l)
+            except:
+                pass
+                
+        l1, = plt.plot(lambds, y)
+        lines.append(l1), labels.append(str(idx))
+    
+    plt.legend(lines,labels)
+    
+    plt.show()
+    
+def plot_scattering_factors():
+    f = StructureFactorFactory().atomic_structure_factor('C')
+    print (f(2))
+    
+
+def eta(Dtheta, cryst):
+    '''
+    Description   : Calculates the eta factor as from Authier, p.136 Eq. 5.31
+    '''
+
+    etaval = (
+               ( Dtheta * np.sin(2*cryst.thetaB) + cryst.chi0*(1-cryst.gamma)/2 )
+               /
+               ( np.sqrt(abs(cryst.gamma))*abs(cryst.c_pol)*np.sqrt(cryst.chih*cryst.chimh) )
+            )
+    return etaval
+
+
+
+
+def xij(Dtheta, cryst):
+    '''
+        Description   : Calculates the xijp factor as from Authier:
+                        Laue  : Eq. 5.36
+                        Bragg : Eq. 5.38
+    '''
+
+    etav = eta(Dtheta, cryst)
+ 
+    if cryst.bragg :
+        xijpval = (-np.sign(cryst.c_pol) / np.sqrt(abs(cryst.gamma)) * np.sqrt(cryst.chih*cryst.chimh)/cryst.chimh * (etav + np.sqrt(etav**2 - 1)))
+        xijppval = (-np.sign(cryst.c_pol) / np.sqrt(abs(cryst.gamma)) * np.sqrt(cryst.chih*cryst.chimh)/cryst.chimh * (etav - np.sqrt(etav**2 - 1)) )
+
+    else :
+        xijpval = (-np.sign(cryst.c_pol) / np.sqrt(cryst.gamma) * np.sqrt(cryst.chih*cryst.chimh)/cryst.chimh * (etav + np.sqrt(etav**2 + 1)) )
+        xijppval = (-np.sign(cryst.c_pol) / np.sqrt(cryst.gamma) * np.sqrt(cryst.chih*cryst.chimh)/cryst.chimh * (etav - np.sqrt(etav**2 + 1)) )
+              
+    return xijpval, xijppval
+
+
+
+
+
+def MP(Dtheta, cryst):
+    '''
+            Description   : Calculates the MPp factor as from Authier p185:
+                        Laue  : Eq. 6.15, Bragg Eq. 7.9
+    '''
+
+    etav = eta(Dtheta, cryst)
+    
+    k = 1./ cryst.lamb
+ 
+    MPpval = (
+                k * cryst.chi0 / ( 2*cryst.gamma0 )
+                + np.sign(cryst.gammah) * etav / ( 2*cryst.pl )
+                - np.sqrt( etav**2 + np.sign(cryst.gammah) ) / ( 2*cryst.pl )
+             )
+    MPppval = (
+                k * cryst.chi0 / ( 2*cryst.gamma0 )
+                + np.sign(cryst.gammah) * etav / ( 2*cryst.pl )
+                + np.sqrt( etav**2 + np.sign(cryst.gammah) ) / ( 2*cryst.pl )
+             )
+
+    return MPpval, MPppval
+
+
+
+'''
+formerly
+D0dfracD0a
+DhdfracD0a
+TODO: add a reference to Authier
+'''
+def D0_Dh(Dtheta, cryst):
+    
+    thick = cryst.size[2]
+ 
+    if cryst.gamma<0:
+        BRAGG = True
+    else:
+        BRAGG = False
+
+
+    cryst.bragg = BRAGG
+    
+    xijpv,  xijppv = xij(Dtheta, cryst)
+    #xijppv = xijpp(Dtheta)
+    MPpv, MPppv   = MP(Dtheta, cryst)
+     
+ 
+    if BRAGG :
+         D0dfracD0aval = (    
+              (xijpv - xijppv) * np.exp( -2*np.pi*1j*(MPpv+MPppv)*thick ) /
+              (  xijpv * np.exp( -2*np.pi*1j*MPpv *thick )
+               - xijppv* np.exp( -2*np.pi*1j*MPppv*thick )
+              )
+         )
+         DhdfracD0aval = (    
+              xijpv * xijppv
+              * ( np.exp( -2*np.pi*1j*MPpv*thick ) - np.exp( -2*np.pi*1j*MPppv*thick ) )
+            /
+              (  xijpv * np.exp( -2*np.pi*1j*MPpv *thick )
+               - xijppv* np.exp( -2*np.pi*1j*MPppv*thick )
+              )
+         )
+
+    else :
+         D0dfracD0aval = (
+              ( xijpv * np.exp( -2*np.pi*1j*MPpv *thick )
+               -xijppv* np.exp( -2*np.pi*1j*MPppv*thick ) ) / (xijpv - xijppv) 
+        )
+         DhdfracD0aval = (
+              ( xijpv * xijppv / (xijppv - xijpv) 
+                * (   np.exp( -2*np.pi*1j*MPpv *thick )
+                    - np.exp( -2*np.pi*1j*MPppv*thick ) )
+               )
+        )
+              
+    return D0dfracD0aval, DhdfracD0aval
+
+
+
+
+
+def transmissivity_reflectivity(klist, cryst):
+    _logger.debug('calculating transmissivity and reflectivity')
+    t  = np.zeros(len(klist),'complex')
+    r  = np.zeros(len(klist),'complex')
+    for i in range(len(klist)):
+        t[i], r[i] = D0_Dh( -(cryst.kb - klist[i]) / ( cryst.kb * (1/np.tan(cryst.thetaB)) ) , cryst)
+    abs_r = abs(r)
+    abs_t = abs(t)
+    if np.nan in abs_t or np.nan in abs_r:
+        _logger.error(ind_str + 'abs(tr) = {}-{}'.format(abs(t[0]), abs(t[-1])))
+        _logger.error(ind_str + 'abs(ref) = {}-{}'.format(abs(r[0]), abs(r[-1])))
+    else:
+        _logger.debug(ind_str + 'abs(tr) = {}-{}'.format(abs(t[0]), abs(t[-1])))
+        _logger.debug(ind_str + 'abs(ref) = {}-{}'.format(abs(r[0]), abs(r[-1])))
+    return t, r
+
+
+def get_crystal_filter(cryst, ev_seed, nk=10000, k = None, n_width = 100):
+    _logger.debug('getting crystal filter')
+    #import crystal as cry
+    
+    #n_width - number of Darwin widths
+    lamb=h_eV_s*speed_of_light/ev_seed
+    ref_idx=cryst.ref_idx
+    n = cryst.cut
+    _logger.debug(ind_str + 'reflection index = {}'.format(ref_idx))
+    kb = 2*np.pi/lamb
+    
+    H, d, phi = find_bragg(lambd = lamb, lattice=cryst.lattice, ord_max = 15)
+    
+    polarization = 'sigma'
+
+    abs_ref_idx = tuple(abs(np.array(ref_idx)))
+    dhkl = d[abs_ref_idx]
+    
+    '''
+    print 'lamb=', lamb
+    print 'thick=', cryst.size[2]
+    print 'd_hkl',d[ref_idx]
+    print 'theta bragg', phi[ref_idx]
+    '''
+    
+    thetaB = phi[abs_ref_idx]* np.pi / 180.0
+    _logger.debug(ind_str + 'Bragg angle {} [rad]'.format(thetaB))
+    _logger.debug(ind_str + 'Bragg angle {} [deg]'.format(thetaB/np.pi*180))
+    
+    if polarization == 'sigma':
+        c_pol = 1
+    else :
+        c_pol = - np.cos(2.0 * thetaB)
+    
+    ref_idx_length = np.sqrt(np.sum(np.array(ref_idx)**2))
+    h_norm = tuple([i/ref_idx_length for i in ref_idx])
+    h = np.array([i*2*np.pi/dhkl for i in h_norm]) # normalized q-vector of crystalline plane
+
+    #quadratic equation coefficients to find incidence angle
+    a = - 0.5 * np.sin(thetaB)**2 + 0.5*h_norm[2]**2
+    b = 2/np.sqrt(2) * (h_norm[0] + h_norm[1]) * h_norm[2]
+    c = - 2 * np.sin(thetaB)**2 + (h_norm[0] + h_norm[1])**2
+
+    ctg2_tilt = np.polynomial.polynomial.polyroots((a,b,c))
+    tilt = np.arctan(ctg2_tilt*2)/np.pi*180
+    tilt_min = tilt[np.argmin(abs(tilt))]
+    _logger.debug(ind_str + 'normal angle = {} deg'.format(calc_angle((0,0,1), n)))
+    _logger.debug(ind_str + 'tilt solutions = {} deg'.format(tilt))
+
+    #s0_0 = np.array([-1*sqrt(2)*np.tan((tilt[0] - 90)/180*np.pi)/2, -1*sqrt(2)*np.tan((tilt[0] - 90)/180*np.pi)/2, -1])
+    s0_0 = np.array([-1*np.sqrt(2)*ctg2_tilt[0], -1*np.sqrt(2)*ctg2_tilt[0], -1])
+    s0_0 = s0_0 / np.linalg.norm(s0_0)
+
+    #s0_1 = np.array([-1*sqrt(2)*np.tan((tilt[1] - 90)/180*np.pi)/2, -1*sqrt(2)*np.tan((tilt[1] - 90)/180*np.pi)/2, -1])
+    s0_1 = np.array([-1*np.sqrt(2)*ctg2_tilt[1], -1*np.sqrt(2)*ctg2_tilt[1], -1])
+    s0_1 = s0_1 / np.linalg.norm(s0_1)
+
+    gamma0_0 = np.dot(n, s0_0)/np.linalg.norm(s0_0)/np.linalg.norm(n)
+    gamma0_1 = np.dot(n, s0_1)/np.linalg.norm(s0_1)/np.linalg.norm(n)
+
+    if gamma0_0 < gamma0_1:
+        s0 = s0_0 * 2 * np.pi / lamb
+        gamma0 = gamma0_0
+    else:
+        s0 = s0_1 * 2 * np.pi / lamb
+        gamma0 = gamma0_1
+
+    #h = np.array(cryst.ref_idx) / np.linalg.norm(cryst.ref_idx) * 2 * np.pi / dhkl
+    sh = s0 + h
+    _logger.debug(ind_str + 'n   = {}'.format(n))
+    _logger.debug(ind_str + 's0 = {}'.format(s0))
+    _logger.debug(ind_str + 'h  = {}'.format(h))
+    _logger.debug(ind_str + 'sh  = {}'.format(sh))
+    
+    
+    gammah = np.dot(n, sh)/np.linalg.norm(sh)/np.linalg.norm(n)
+    
+    gamma0, gammah = -gamma0, -gammah ####bugfix?
+    
+    gamma = gamma0 / gammah
+
+    _logger.debug(ind_str + '2 theta = {} deg'.format(calc_angle(s0,-sh)))
+    _logger.debug(ind_str + 'angle s0 to -n (0==best): {}'.format(np.arccos(gamma0)/np.pi*180))
+    _logger.debug(ind_str + 'angle sh to -n (90==worst?): {}'.format(180 - np.arccos(gammah)/np.pi*180))
+
+    #################
+    # cryst.psi_n=-np.pi/2
+    # psih   = cryst.psi_n - thetaB
+    # psi0   = cryst.psi_n + thetaB
+    # gamma0 = np.cos(psi0)
+    # gammah = np.cos(psih)
+    # gamma  = gammah/gamma0
+    ###################
+    
+    _logger.debug(ind_str + 'gamma0: {}'.format(gamma0))
+    _logger.debug(ind_str + 'gammah: {}'.format(gammah))
+    _logger.debug(ind_str + 'gamma: {}'.format(gamma))
+    if gamma<0:
+        _logger.debug(2*ind_str + 'BRAGG geometry')
+    else:
+        _logger.warning(2*ind_str + 'LAUE geometry')
+
+
+    
+    f0, fh, fmh =  F_hkl(cryst = cryst, ref_idx = abs_ref_idx, lamb=lamb, temp = 300*K)
+    
+    
+#    _logger.debug(ind_str + 'structure factors {} {} {}'.format(f0, fh, fmh))
+    #plt.figure()
+
+     
+        
+    vcell = ( dhkl * np.sqrt( np.dot(ref_idx,ref_idx) ) ) **3
+        
+    delta    = r_el * np.abs(c_pol) * lamb**2 * np.sqrt( np.abs(gamma)*fh*fmh ) / ( np.pi * vcell * np.sin(2*thetaB) )
+    mid_TH = np.real( r_el * lamb**2 * f0 * (1-gamma) / (2*np.pi * vcell * np.sin(2*thetaB)) )
+    mid_k  = kb / (- mid_TH * 1/np.tan(thetaB) + 1 )
+    dk  =  ( -2*kb*np.sin(thetaB) + np.sqrt(16*mid_k**2 * np.real(delta)**2 * np.cos(thetaB)**2 + 4*kb**2 * np.sin(thetaB)**2) ) / ( 2 * np.real(delta) * np.cos(thetaB) )
+    
+    print('vcell', vcell)
+    print('mid_k', mid_k)
+    
+    ki, kf = mid_k - n_width*dk, mid_k + n_width*dk    #final   k    
+    
+    if k == None:    
+        k = np.linspace(ki, kf, nk)    
+        
+    
+    cryst.lamb = lamb
+    cryst.kb = kb
+    cryst.kb = 2 * kb - mid_k # bugfix
+    cryst.thetaB = thetaB
+    cryst.gamma = gamma
+    cryst.gamma0 = gamma0
+    cryst.gammah = gammah
+    cryst.c_pol = c_pol
+    cryst.chi0  = - ( r_el * lamb**2 * f0  ) / ( np.pi * vcell )
+    cryst.chih  = - ( r_el * lamb**2 * fh  ) / ( np.pi * vcell )
+    cryst.chimh = - ( r_el * lamb**2 * fmh ) / ( np.pi * vcell )
+    cryst.pl = np.pi * vcell * np.sqrt( gamma0 * np.abs(gammah) ) / ( r_el * lamb * np.abs(c_pol) * np.sqrt( fh*fmh ) )
+    
+    
+    from ocelot.optics.wave import TransferFunction #hotfix here
+    f = TransferFunction()
+    
+    f.tr, f.ref = transmissivity_reflectivity(k, cryst)   
+    
+    f.k = k
+    f.thetaB = thetaB
+    f.mid_k = mid_k
+    f.dk = dk
+    f.xlamds = lamb
+    f.cryst = cryst
+    return f
+
+
+
+def unfold_angles(Phlist):
+    '''
+    
+    '''
+
+    NK = len(Phlist)
+    Phout  = np.zeros(NK)
+    
+    Phout[0] = Phlist[0] 
+    count  = 0.0
+    for i in range(1,NK):
+        count = count + np.floor( (Phlist[i]-Phlist[i-1])/(2*np.pi) + 0.5 )
+        Phout[i] = Phlist[i] - 2*np.pi*count
+
+    return Phout
+
+
+if __name__ == "__main__":
+    plot_bragg_reflections()
+    #plot_scattering_factors()
+    
\ No newline at end of file
diff --git a/ocelot/optics/data/C004.dat b/ocelot/optics/data/C004.dat
new file mode 100644
index 00000000..d847e5a3
Binary files /dev/null and b/ocelot/optics/data/C004.dat differ
diff --git a/ocelot/optics/new_wave.py b/ocelot/optics/new_wave.py
new file mode 100644
index 00000000..b1e562e0
--- /dev/null
+++ b/ocelot/optics/new_wave.py
@@ -0,0 +1,1364 @@
+"""
+wave optics 
+an alternative .py file to wave.py
+includes basic classes of RadiationField 
+modified for new ocelot beamline architecture
+"""
+
+from numpy import random
+from numpy.linalg import norm
+import numpy as np
+from math import factorial
+from numpy import inf, complex128, complex64
+import scipy
+import numpy.fft as fft
+from copy import deepcopy
+import time
+import os
+
+# from ocelot.optics.elements import *
+from ocelot.common.globals import *
+from ocelot.common.math_op import find_nearest_idx, fwhm, std_moment, bin_scale, bin_array, mut_coh_func
+from ocelot.common.py_func import filename_from_path
+# from ocelot.optics.utils import calc_ph_sp_dens
+# from ocelot.adaptors.genesis import *
+# import ocelot.adaptors.genesis as genesis_ad
+# GenesisOutput = genesis_ad.GenesisOutput
+from ocelot.common.ocelog import *
+_logger = logging.getLogger(__name__)
+
+import multiprocessing
+nthread = multiprocessing.cpu_count()
+
+try:
+    import pyfftw
+    fftw_avail = True
+except ImportError:
+    print("wave.py: module PYFFTW is not installed. Install it if you want speed up dfl wavefront calculations")
+    fftw_avail = False
+
+__author__ = "Svitozar Serkez, Andrei Trebushinin, Mykola Veremchuk"
+
+
+
+class Grid:
+    """
+    Grid object defines spatial-frequency 3D mesh for Radiation Field class and Mask class    
+    :params (dx, dy, dz): spatial step of the mesh 
+    :param shape: number of point in each direction of 3D data mesh
+    :param xlamds: carrier wavelength of the wavepacket
+    :param used_aprox: the approximation used in solving the wave equation. 
+    OCELOT works in Slowly-Varyinig Envelope Approximation (SVEA)
+    """
+    def __init__(self, shape=(0,0,0)):
+        self.dx = []
+        self.dy = []
+        self.dz = []
+        self.xlamds = None
+        self.domain_z = 't'   # longitudinal domain (t - time, f - frequency)
+        self.domain_x = 's'   # transverse domain (s - space, k - inverse space)
+        self.domain_y = 's'   # transverse domain (s - space, k - inverse space)
+        self.domain_xy = 's'  # transverse domain (s - space, k - inverse space)
+        self.used_aprox = 'SVEA'
+
+    def copy_grid(self, other, version=2):
+        """
+        TODO
+        write documentation
+        """
+        if version == 1:
+            self.dx = other.dx
+            self.dy = other.dy
+            self.dz = other.dz
+            self.shape = other.shape
+            
+            self.xlamds = other.xlamds
+            self.used_aprox = other.used_aprox
+            
+        elif version == 2: #Setting attributes with the same memory may also be a good idea
+        # address for Mask and RadiationField objects, to synchronize these object attributes "automatically"
+            attr_list = np.intersect1d(dir(self),dir(other))
+            for attr in attr_list:
+                if attr.startswith('__') or callable(getattr(self, attr)):
+                    continue
+                setattr(self, attr, getattr(other, attr))
+        else:
+            raise ValueError
+    
+    def shape(self):
+        
+        if 'fld' in self.__dict__:
+        
+            return self.fld.shape
+        
+        elif 'msk' in self.__dict__:
+            
+            return self.msk.shape
+        
+        else:        
+            raise KeyError('in the __dict__ must be either "fld" or "msk"')
+            
+    def Lz(self):  
+        '''
+        full longitudinal mesh size
+        '''
+        return self.dz * self.Nz()
+
+    def Ly(self):  
+        '''
+        full transverse vertical mesh size
+        '''
+        return self.dy * self.Ny()
+
+    def Lx(self):  
+        '''
+        full transverse horizontal mesh size
+        '''
+        return self.dx * self.Nx()
+
+    def Nz(self):
+        '''
+        number of points in z
+        '''
+        return self.shape()[0]
+
+    def Ny(self):
+        '''
+        number of points in y
+        '''
+        return self.shape()[1]
+
+    def Nx(self):
+        '''
+        number of points in x
+        '''
+        return self.shape()[2]
+    
+    def grid_x(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        return np.linspace(-self.Lx() / 2, self.Lx() / 2, self.Nx())
+    
+    def grid_kx(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        
+        k = 2 * np.pi / self.dx
+        return np.linspace(-k / 2, k / 2, self.Nx())
+    
+    def grid_y(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        
+        return np.linspace(-self.Ly() / 2, self.Ly() / 2, self.Ny())
+    
+    def grid_ky(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        k = 2 * np.pi / self.dy
+        return np.linspace(-k / 2, k / 2, self.Ny())
+          
+    def grid_z(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        return np.linspace(0, self.Lz(), self.Nz())
+    
+    def grid_kz(self):
+        '''
+
+        Returns
+        -------
+        TYPE
+            DESCRIPTION.
+
+        '''
+        dk = 2 * pi / self.Lz()
+        k = 2 * pi / self.xlamds       
+        return np.linspace(k - dk / 2 * self.Nz(), k + dk / 2 * self.Nz(), self.Nz())    
+
+class RadiationField(Grid):
+    """
+    3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+    """
+
+    def __init__(self, shape=(0,0,0)):
+        Grid.__init__(self, shape=shape)
+        self.fld = np.zeros(shape, dtype=complex128)  # (z,y,x)
+        self.xlamds = None    # carrier wavelength [m]
+        # self.domain_z = 't'   # longitudinal domain (t - time, f - frequency)
+        # self.domain_x = 's'   # transverse domain (s - space, k - inverse space)
+        # self.domain_y = 's'   # transverse domain (s - space, k - inverse space)
+        # self.domain_xy = 's'  # transverse domain (s - space, k - inverse space)
+        self.filePath = ''
+                      
+    def fileName(self):
+        return filename_from_path(self.filePath)
+
+    def copy_param(self, dfl1, version=1):
+        if version == 1:
+            self.dx = dfl1.dx
+            self.dy = dfl1.dy
+            self.dz = dfl1.dz
+            self.xlamds = dfl1.xlamds
+            self.domain_z = dfl1.domain_z
+            self.domain_x = dfl1.domain_x
+            self.domain_y = dfl1.domain_y
+
+            self.domain_xy = dfl1.domain_xy
+            self.filePath = dfl1.filePath
+        elif version == 2: #does it link the address of these two objects only? : _) then exactly what we need for grid copying
+            attr_list = dir(dfl1)
+            for attr in attr_list:
+                if attr.startswith('__') or callable(getattr(self, attr)):
+                    continue
+                if attr == 'fld':
+                    continue
+                setattr(self, attr, getattr(dfl1, attr))
+
+    def __getitem__(self, i):
+        return self.fld[i]
+
+    def __setitem__(self, i, fld):
+        self.fld[i] = fld
+
+    # def shape(self):
+    #     '''
+    #     returns the shape of fld attribute
+    #     '''
+    #     return self.fld.shape
+
+    def domains(self):
+        '''
+        returns domains of the radiation field
+        '''
+        return self.domain_z, self.domain_xy
+
+    def intensity(self):
+        '''
+        3d intensity, abs(fld)**2
+        '''
+        return self.fld.real ** 2 + self.fld.imag ** 2 # calculates faster
+
+    def int_z(self):
+        '''
+        intensity projection on z
+        power [W] or spectral density [arb.units]
+        '''
+        return np.sum(self.intensity(), axis=(1, 2))
+
+    def ang_z_onaxis(self):
+        '''
+        on-axis phase
+        '''
+        xn = int((self.Nx() + 1) / 2)
+        yn = int((self.Ny() + 1) / 2)
+        fld = self[:, yn, xn]
+        return np.angle(fld)
+
+    def int_y(self):
+        '''
+        intensity projection on y
+        '''
+        return np.sum(self.intensity(), axis=(0, 2))
+
+    def int_x(self):
+        '''
+        intensity projection on x
+        '''
+        return np.sum(self.intensity(), axis=(0, 1))
+
+    def int_xy(self):
+        # return np.swapaxes(np.sum(self.intensity(), axis=0), 1, 0)
+        return np.sum(self.intensity(), axis=0)
+
+    def int_zx(self):
+        return np.sum(self.intensity(), axis=1)
+
+    def int_zy(self):
+        return np.sum(self.intensity(), axis=2)
+
+    def E(self):
+        '''
+        energy in the pulse [J]
+        '''
+        if self.Nz() > 1:
+            return np.sum(self.intensity()) * self.Lz() / self.Nz() / speed_of_light
+        else:
+            return np.sum(self.intensity())
+
+    def scale_kx(self):  # scale in meters or meters**-1
+        _logger.warning('"scale_kx" will be deprecated, use "grid_x and grid_kx" instead')
+
+#        if 's' in [self.domain_xy, self.domain_x]:    # space domain
+        if self.domain_xy == 's':    # space domain
+            return self.grid_x()        
+
+#        elif 'k' in [self.domain_xy, self.domain_x]:  # inverse space domain
+        elif self.domain_xy == 'k':  # inverse space domain
+            return self.grid_kx()
+       
+        else:
+            raise AttributeError('Wrong domain_xy attribute')
+
+    def scale_ky(self):  # scale in meters or meters**-1
+        _logger.warning('"scale_ky" will be deprecated, use "grid_y and grid_ky" instead')
+#        if 's' in [self.domain_xy, self.domain_y]:    # space domain
+        if self.domain_xy == 's':    # space domain
+            return self.grid_y()
+#        elif 'k' in [self.domain_xy, self.domain_y]:  # inverse space domain
+        if self.domain_xy == 'k':    # space domain
+            return self.grid_ky()
+        else:
+            raise AttributeError('Wrong domain_xy attribute')
+    
+    def scale_kz(self):  # scale in meters or meters**-1
+        _logger.warning('"scale_kz" will be deprecated, use "grid_z and grid_kz" instead')        
+        if self.domain_z == 't':  # time domain
+            return self.grid_z()
+        elif self.domain_z == 'f':  # frequency domain
+            return self.grid_kz()
+        else:
+            raise AttributeError('Wrong domain_z attribute')
+
+    def scale_x(self):  # scale in meters or radians
+#        _logger.warning('"scale_x" will be deprecated, use "grid_x and grid_kx" instead')        
+        if self.domain_xy == 's':  # space domain
+            return self.scale_kx()
+        elif self.domain_xy == 'k':  # inverse space domain
+            return self.scale_kx() * self.xlamds / 2 / np.pi
+        else:
+            raise AttributeError('Wrong domain_xy attribute')
+
+    def scale_y(self):  # scale in meters or radians
+        if self.domain_xy == 's':  # space domain
+            return self.scale_ky()
+        elif self.domain_xy == 'k':  # inverse space domain
+            return self.scale_ky() * self.xlamds / 2 / np.pi
+        else:
+            raise AttributeError('Wrong domain_xy attribute')
+
+    def scale_z(self):  # scale in meters
+        if self.domain_z == 't':  # time domain
+            return self.scale_kz()
+        elif self.domain_z == 'f':  # frequency domain
+            return 2 * pi / self.scale_kz()
+        else:
+            raise AttributeError('Wrong domain_z attribute')
+
+    def ph_sp_dens(self):
+        if self.domain_z == 't':
+            dfl = deepcopy(self)
+            dfl.fft_z()
+        else:
+            dfl = self
+        pulse_energy = dfl.E()
+        spec0 = dfl.int_z()
+        freq_ev = h_eV_s * speed_of_light / dfl.scale_z()
+        freq_ev_mean = np.sum(freq_ev * spec0) / np.sum(spec0)
+        n_photons = pulse_energy / q_e / freq_ev_mean
+        spec = calc_ph_sp_dens(spec0, freq_ev, n_photons)
+        return freq_ev, spec
+
+    def to_domain(self, domains='ts', **kwargs):
+        """
+        tranfers radiation to specified domains
+        *domains is a string with one or two letters:
+            ("t" or "f") and ("s" or "k")
+        where
+            't' (time); 'f' (frequency); 's' (space); 'k' (inverse space);
+        e.g.
+            't'; 'f'; 's'; 'k'; 'ts'; 'fs'; 'tk'; 'fk'
+        order does not matter
+
+        **kwargs are passed down to self.fft_z and self.fft_xy
+        """
+        _logger.debug('transforming radiation field to {} domain'.format(str(domains)))
+        dfldomain_check(domains)
+
+        for domain in domains:
+            domain_o_z, domain_o_xy = self.domain_z, self.domain_xy
+            if domain in ['t', 'f'] and domain is not domain_o_z:
+                self.fft_z(**kwargs)
+            if domain in ['s', 'k'] and domain is not domain_o_xy:
+                self.fft_xy(**kwargs)
+
+    def fft_z(self, method='mp', nthread=multiprocessing.cpu_count(),
+              **kwargs):  # move to another domain ( time<->frequency )
+        _logger.debug('calculating dfl fft_z from ' + self.domain_z + ' domain with ' + method)
+        start = time.time()
+        orig_domain = self.domain_z
+        
+        if nthread < 2:
+            method = 'np'
+        
+        if orig_domain == 't':
+            if method == 'mp' and fftw_avail:
+                fft_exec = pyfftw.builders.fft(self.fld, axis=0, overwrite_input=True, planner_effort='FFTW_ESTIMATE',
+                                               threads=nthread, auto_align_input=False, auto_contiguous=False,
+                                               avoid_copy=True)
+                self.fld = fft_exec()
+            else:
+                self.fld = np.fft.fft(self.fld, axis=0)
+            # else:
+            #     raise ValueError('fft method should be "np" or "mp"')
+            self.fld = np.fft.ifftshift(self.fld, 0)
+            self.fld /= np.sqrt(self.Nz())
+            self.domain_z = 'f'
+        elif orig_domain == 'f':
+            self.fld = np.fft.fftshift(self.fld, 0)
+            if method == 'mp' and fftw_avail:
+                fft_exec = pyfftw.builders.ifft(self.fld, axis=0, overwrite_input=True, planner_effort='FFTW_ESTIMATE',
+                                                threads=nthread, auto_align_input=False, auto_contiguous=False,
+                                                avoid_copy=True)
+                self.fld = fft_exec()
+            else:
+                self.fld = np.fft.ifft(self.fld, axis=0)
+                
+                # else:
+                # raise ValueError("fft method should be 'np' or 'mp'")
+            self.fld *= np.sqrt(self.Nz())
+            self.domain_z = 't'
+        else:
+            raise ValueError("domain_z value should be 't' or 'f'")
+        
+        t_func = time.time() - start
+        if t_func < 60:
+            _logger.debug(ind_str + 'done in %.2f sec' % (t_func))
+        else:
+            _logger.debug(ind_str + 'done in %.2f min' % (t_func / 60))
+
+    def fft_xy(self, method='mp', nthread=multiprocessing.cpu_count(),
+               **kwargs):  # move to another domain ( spce<->inverse_space )
+        _logger.debug('calculating fft_xy from ' + self.domain_xy + ' domain with ' + method)
+        start = time.time()
+        domain_orig = self.domain_xy
+
+        if nthread < 2:
+            method = 'np'
+        
+        if domain_orig == 's':
+            if method == 'mp' and fftw_avail:
+                fft_exec = pyfftw.builders.fft2(self.fld, axes=(1, 2), overwrite_input=False,
+                                                planner_effort='FFTW_ESTIMATE', threads=nthread, auto_align_input=False,
+                                                auto_contiguous=False, avoid_copy=True)
+                self.fld = fft_exec()
+            else:
+                self.fld = np.fft.fft2(self.fld, axes=(1, 2))
+                # else:
+                # raise ValueError("fft method should be 'np' or 'mp'")
+            self.fld = np.fft.fftshift(self.fld, axes=(1, 2))
+            self.fld /= np.sqrt(self.Nx() * self.Ny())
+            self.domain_xy = 'k'
+        elif domain_orig == 'k':
+            self.fld = np.fft.ifftshift(self.fld, axes=(1, 2))
+            if method == 'mp' and fftw_avail:
+                fft_exec = pyfftw.builders.ifft2(self.fld, axes=(1, 2), overwrite_input=False,
+                                                 planner_effort='FFTW_ESTIMATE', threads=nthread,
+                                                 auto_align_input=False, auto_contiguous=False, avoid_copy=True)
+                self.fld = fft_exec()
+            else:
+                self.fld = np.fft.ifft2(self.fld, axes=(1, 2))
+            # else:
+            #     raise ValueError("fft method should be 'np' or 'mp'")
+            self.fld *= np.sqrt(self.Nx() * self.Ny())
+            self.domain_xy = 's'
+        
+        else:
+            raise ValueError("domain_xy value should be 's' or 'k'")
+        
+        t_func = time.time() - start
+        if t_func < 60:
+            _logger.debug(ind_str + 'done in %.2f sec' % (t_func))
+        else:
+            _logger.debug(ind_str + 'done in %.2f min' % (t_func / 60))
+    
+
+    def mut_coh_func(self, norm=1, jit=1):
+        '''
+        calculates mutual coherence function
+        consider downsampling the field first
+        '''
+        if jit:
+            J = np.zeros([self.Ny(), self.Nx(), self.Ny(), self.Nx()]).astype(np.complex128)
+            mut_coh_func(J, self.fld, norm=norm)
+        else:
+            I = self.int_xy() / self.Nz()
+            J = np.mean(
+                self.fld[:, :, :, np.newaxis, np.newaxis].conjugate() * self.fld[:, np.newaxis, np.newaxis, :, :],
+                axis=0)
+            if norm:
+                J /= (I[:, :, np.newaxis, np.newaxis] * I[np.newaxis, np.newaxis, :, :])
+        return J
+    
+    def coh(self, jit=0):
+        '''
+        calculates degree of transverse coherence
+        consider downsampling the field first
+        '''
+        I = self.int_xy() / self.Nz()
+        J = self.mut_coh_func(norm=0, jit=jit)
+        coh = np.sum(abs(J) ** 2) / np.sum(I) ** 2
+        return coh
+        
+    def tilt(self, angle=0, plane='x', return_orig_domains=True):
+        '''
+        deflects the radaition in given direction by given angle
+        by introducing transverse phase chirp
+        '''
+        _logger.info('tilting radiation by {:.4e} rad in {} plane'.format(angle, plane))
+        _logger.warn(ind_str + 'in beta')
+        angle_warn = ind_str + 'deflection angle exceeds inverse space mesh range'
+        
+        k = 2 * pi / self.xlamds
+        domains = self.domains()
+        
+        self.to_domain('s')
+        if plane == 'y':
+            if np.abs(angle) > self.xlamds / self.dy / 2:
+                _logger.warning(angle_warn)
+            dphi =  angle * k * self.scale_y()
+            self.fld = self.fld * np.exp(1j * dphi)[np.newaxis, :, np.newaxis]
+        elif plane == 'x':
+            if np.abs(angle) > self.xlamds / self.dx / 2:
+                _logger.warning(angle_warn)
+            dphi =  angle * k * self.scale_x()
+            self.fld = self.fld * np.exp(1j * dphi)[np.newaxis, np.newaxis, :]
+        else:
+            raise ValueError('plane should be "x" or "y"')
+            
+        if return_orig_domains:
+            self.to_domain(domains)
+    
+            
+    def disperse(self, disp=0, E_ph0=None, plane='x', return_orig_domains=True):
+        '''
+        introducing angular dispersion in given plane by deflecting the radaition by given angle depending on its frequency
+        disp is the dispertion coefficient [rad/eV]
+        E_ph0 is the photon energy in [eV] direction of which would not be changed (principal ray)
+        '''
+        _logger.info('introducing dispersion of {:.4e} [rad/eV] in {} plane'.format(disp, plane))
+        _logger.warn(ind_str + 'in beta')
+        angle_warn = ind_str + 'deflection angle exceeds inverse space mesh range'
+        if E_ph0 == None:
+            E_ph0 = 2 *np.pi / self.xlamds * speed_of_light * hr_eV_s
+        
+        dk = 2 * pi / self.Lz()
+        k = 2 * pi / self.xlamds        
+        phen = np.linspace(k - dk / 2 * self.Nz(), k + dk / 2 * self.Nz(), self.Nz()) * speed_of_light * hr_eV_s
+        angle = disp * (phen - E_ph0)
+        
+        if np.amax([np.abs(np.min(angle)), np.abs(np.max(angle))]) > self.xlamds / self.dy / 2:
+            _logger.warning(angle_warn)
+        
+        domains = self.domains()
+        self.to_domain('sf')
+        if plane =='y':
+            dphi =  angle[:,np.newaxis] * k * self.scale_y()[np.newaxis, :]
+            self.fld = self.fld * np.exp(1j *dphi)[:, :, np.newaxis]
+        elif plane == 'x':
+            dphi =  angle[:,np.newaxis] * k * self.scale_x()[np.newaxis, :]
+            self.fld = self.fld * np.exp(1j *dphi)[:, np.newaxis, :]
+        
+        if return_orig_domains:
+            self.to_domain(domains)
+            
+    def curve_wavefront(self, r=np.inf, plane='xy', domain_z=None):
+        """
+        introduction of the additional
+        wavefront curvature with radius r
+
+        r can be scalar or vector with self.Nz() points
+        r>0 -> converging wavefront
+
+        plane is the plane in which wavefront is curved:
+            'x' - horizontal focusing
+            'y' - vertical focusing
+            'xy' - focusing in both planes
+
+        domain_z is the domain in which wavefront curvature is introduced
+            'f' - frequency
+            't' - time
+            None - original domain (default)
+
+        """
+
+        domains = domain_o_z, domain_o_xy = self.domain_z, self.domain_xy
+
+        if domain_z == None:
+            domain_z = domain_o_z
+
+        _logger.debug('curving radiation wavefront by {}m in {} domain'.format(r, domain_z))
+
+        if np.size(r) == 1:
+            if r == 0:
+                _logger.error(ind_str + 'radius of curvature should not be zero')
+                raise ValueError('radius of curvature should not be zero')
+            elif r == np.inf:
+                _logger.debug(ind_str + 'radius of curvature is infinite, skipping')
+                return
+            else:
+                pass
+
+        if domain_z == 'f':
+            self.to_domain('fs')
+            x, y = np.meshgrid(self.scale_x(), self.scale_y())
+            if plane == 'xy' or plane == 'yx':
+                arg2 = x ** 2 + y ** 2
+            elif plane == 'x':
+                arg2 = x ** 2
+            elif plane == 'y':
+                arg2 = y ** 2
+            else:
+                _logger.error('"plane" should be in ["x", "y", "xy"]')
+                raise ValueError()
+            k = 2 * np.pi / self.scale_z()
+            if np.size(r) == 1:
+                self.fld *= np.exp(-1j * k[:, np.newaxis, np.newaxis] / 2 * arg2[np.newaxis, :, :] / r)
+            elif np.size(r) == self.Nz():
+                self.fld *= np.exp(
+                    -1j * k[:, np.newaxis, np.newaxis] / 2 * arg2[np.newaxis, :, :] / r[:, np.newaxis, np.newaxis])
+
+        elif domain_z == 't':
+            self.to_domain('ts')
+            x, y = np.meshgrid(self.scale_x(), self.scale_y())
+            if plane == 'xy' or plane == 'yx':
+                arg2 = x ** 2 + y ** 2
+            elif plane == 'x':
+                arg2 = x ** 2
+            elif plane == 'y':
+                arg2 = y ** 2
+            else:
+                _logger.error('"plane" should be in ["x", "y", "xy"]')
+                raise ValueError()
+            k = 2 * np.pi / self.xlamds
+            if np.size(r) == 1:
+                self.fld *= np.exp(-1j * k / 2 * arg2 / r)[np.newaxis, :, :]
+            elif np.size(r) == self.Nz():
+                self.fld *= np.exp(-1j * k / 2 * arg2[np.newaxis, :, :] / r[:, np.newaxis, np.newaxis])
+            else:
+                raise ValueError('wrong dimensions of radius of curvature')
+        else:
+            ValueError('domain_z should be in ["f", "t", None]')
+
+        self.to_domain(domains)
+
+    def prop(self, z, fine=1, return_result=0, return_orig_domains=1, **kwargs):
+        """
+        Angular-spectrum propagation for fieldfile
+        
+        can handle wide spectrum
+          (every slice in freq.domain is propagated
+           according to its frequency)
+        no kx**2+ky**2<<k0**2 limitation
+        
+        dfl is the RadiationField() object
+        z is the propagation distance in [m]
+        fine=1 is a flag for ~2x faster propagation.
+            no Fourier transform to frequency domain is done
+            assumes no angular dispersion (true for plain FEL radiation)
+            assumes narrow spectrum at center of xlamds (true for plain FEL radiation)
+        
+        return_result does not modify self, but returns result
+        
+        z>0 -> forward direction
+        """
+        _logger.info('propagating dfl file by %.2f meters' % (z))
+        
+        if z == 0:
+            _logger.debug(ind_str + 'z=0, returning original')
+            if return_result:
+                return self
+            else:
+                return
+        
+        start = time.time()
+        
+        domains = self.domains()
+        
+        if return_result:
+            copydfl = deepcopy(self)
+            copydfl, self = self, copydfl
+        
+        if fine == 1:
+            self.to_domain('kf')
+        elif fine == -1:
+            self.to_domain('kt')
+        else:
+            self.to_domain('k')
+        
+        if self.domain_z == 'f':
+            k_x, k_y = np.meshgrid(self.scale_kx(), self.scale_ky())
+            k = self.scale_kz()
+            # H = np.exp(1j * z * (np.sqrt((k**2)[:,np.newaxis,np.newaxis] - (k_x**2)[np.newaxis,:,:] - (k_y**2)[np.newaxis,:,:]) - k[:,np.newaxis,np.newaxis]))
+            # self.fld *= H
+            for i in range(self.Nz()):  # more memory efficient
+                H = np.exp(1j * z * (np.sqrt(k[i] ** 2 - k_x ** 2 - k_y ** 2) - k[i]))
+                self.fld[i, :, :] *= H
+        else:
+            k_x, k_y = np.meshgrid(self.scale_kx(), self.scale_ky())
+            k = 2 * np.pi / self.xlamds
+            H = np.exp(1j * z * (np.sqrt(k ** 2 - k_x ** 2 - k_y ** 2) - k))
+            # self.fld *= H[np.newaxis,:,:]
+            for i in range(self.Nz()):  # more memory efficient
+                self.fld[i, :, :] *= H
+        
+        if return_orig_domains:
+            self.to_domain(domains)
+        
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in %.2f sec' % t_func)
+        
+        if return_result:
+            copydfl, self = self, copydfl
+            return copydfl
+        
+    def prop_m(self, z, m=1, fine=1, return_result=0, return_orig_domains=1, **kwargs):
+        """
+        Angular-spectrum propagation for fieldfile
+        
+        can handle wide spectrum
+          (every slice in freq.domain is propagated
+           according to its frequency)
+        no kx**2+ky**2<<k0**2 limitation
+        
+        dfl is the RadiationField() object
+        z is the propagation distance in [m]
+        m is the output mesh size in terms of input mesh size (m = L_out/L_inp)
+        which can be a number m or a pair of number m = [m_x, m_y]
+        fine==0 is a flag for ~2x faster propagation.
+            no Fourier transform to frequency domain is done
+            assumes no angular dispersion (true for plain FEL radiation)
+            assumes narrow spectrum at center of xlamds (true for plain FEL radiation)
+        
+        z>0 -> forward direction
+        """
+        _logger.info('propagating dfl file by %.2f meters' % (z))
+        
+        start = time.time()
+        domains = self.domains()
+        
+        if return_result:
+            copydfl = deepcopy(self)
+            copydfl, self = self, copydfl
+        
+        domain_z = self.domain_z
+        if np.size(m)==1:
+            m_x = m
+            m_y = m
+        elif np.size(m)==2:
+            m_x = m[0]
+            m_y = m[1]
+        else:
+            _logger.error(ind_str + 'm mast have shape = 1 or 2')
+            raise ValueError('m mast have shape = 1 or 2')
+             
+        if z==0:
+            _logger.debug(ind_str + 'z=0, returning original')
+            if m_x != 1 and m_y != 1:
+                _logger.debug(ind_str + 'mesh is not resized in the case z = 0')
+            if return_result:
+                return self
+            else:
+                return
+        
+        if m_x != 1:
+            self.curve_wavefront(-z / (1 - m_x), plane='x')
+        if m_y != 1:
+            self.curve_wavefront(-z / (1 - m_y), plane='y')
+        
+        if fine == 1:
+            self.to_domain('kf')
+        elif fine == -1:
+            self.to_domain('kt')
+        else:
+            self.to_domain('k')
+        
+        if z != 0:
+            H = 1
+            if self.domain_z == 'f':
+                k_x, k_y = np.meshgrid(self.scale_kx(), self.scale_ky())
+                k = self.scale_kz()
+                # H = np.exp(1j * z * (np.sqrt((k**2)[:,np.newaxis,np.newaxis] - (k_x**2)[np.newaxis,:,:] - (k_y**2)[np.newaxis,:,:]) - k[:,np.newaxis,np.newaxis]))
+                # self.fld *= H
+                #for i in range(self.Nz()):
+                #    H = np.exp(1j * z / m * (np.sqrt(k[i] ** 2 - k_x ** 2 - k_y ** 2) - k[i]))
+                #    self.fld[i, :, :] *= H
+                if m_x != 0:
+                    for i in range(self.Nz()):
+                        H=np.exp(1j * z / m_x * (np.sqrt(k[i] ** 2 - k_x ** 2) - k[i]))
+                        self.fld[i, :, :] *= H
+                if m_y != 0:
+                    for i in range(self.Nz()):
+                        H=np.exp(1j * z / m_y * (np.sqrt(k[i] ** 2 - k_y ** 2) - k[i]))
+                        self.fld[i, :, :] *= H           
+            else:
+                k_x, k_y = np.meshgrid(self.scale_kx(), self.scale_ky())
+                k = 2 * np.pi / self.xlamds
+                if m_x != 0:
+                    H*=np.exp(1j * z / m_x * (np.sqrt(k ** 2 - k_x ** 2) - k))                
+                if m_y != 0:
+                    H*=np.exp(1j * z / m_y * (np.sqrt(k ** 2 - k_y ** 2) - k))
+                for i in range(self.Nz()):
+                    self.fld[i, :, :] *= H
+        
+        self.dx *= m_x
+        self.dy *= m_y
+        
+        if return_orig_domains:
+            self.to_domain(domains)
+        if m_x != 1:
+            self.curve_wavefront(-m_x * z / (m_x - 1), plane='x')
+        if m_y != 1:
+            self.curve_wavefront(-m_y * z / (m_y - 1), plane='y')
+        
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in %.2f sec' % (t_func))
+        
+        if return_result:
+            copydfl, self = self, copydfl
+            return copydfl
+        
+class HeightProfile: # this one is here because generate_1d_profile is a method
+    """
+    1d surface of mirror
+    """
+
+    def __init__(self):
+        self.N = None #points number
+        self.L = None #length of the surface
+        self.h = None #height profile
+        self.s = None #np.linspace(-L / 2, L / 2, N)
+
+    def hrms(self):
+        return np.sqrt(np.mean(np.square(self.h)))
+
+    def set_hrms(self, rms):
+        self.h *= rms / self.hrms()
+
+    def psd(self):
+        psd = 1 / (self.L * np.pi) * np.square(np.abs(np.fft.fft(self.h) * self.L / self.N))
+        psd = psd[:len(psd) // 2]
+        k = np.pi / self.L * np.linspace(0, self.N, self.N // 2)
+        # k = k[len(k) // 2:]
+        return (k, psd)
+    
+    def generate_1d_profile(self, hrms, L=0.1, N=1000, k_cut=0, psd=None, seed=None):
+        """
+        Method for generating HeightProfile of highly polished mirror surface
+    
+        :param hrms: [meters] height errors root mean square
+        :param L: [meters] length of the surface
+        :param N: number of points (pixels) at the surface
+        :param k_cut: [1/meters] point on k axis for cut off small wavevectors (large wave lengths) in the PSD
+                                        (with default value 0 effects on nothing)
+        :param psd: [meters^3] 1d array; power spectral density of surface (if not specified, will be generated)
+                (if specified, must have shape = (points_number // 2 + 1, ), otherwise it will be cut to appropriate shape)
+        :param seed: seed for np.random.seed() to allow reproducibility
+        :return: HeightProfile object
+        """
+    
+        _logger.info('generating 1d surface with rms: {} m; and shape: {}'.format(hrms, (N,)))
+        _logger.warning(ind_str + 'in beta')
+    
+        # getting the heights map
+        if seed is not None:
+            np.random.seed(seed)
+            
+        if psd is None:
+            k = np.pi / L * np.linspace(0, N, N // 2 + 1)
+            # defining linear function PSD(k) in loglog plane
+            a = -2  # free term of PSD(k) in loglog plane
+            b = -2  # slope of PSD(k) in loglog plane
+            psd = np.exp(a * np.log(10)) * np.exp(b * np.log(k[1:]))
+            psd = np.append(psd[0], psd)  # ??? It doesn*t important, but we need to add that for correct amount of points
+            if k_cut != 0:
+                idx = find_nearest_idx(k, wavevector_cutoff)
+                psd = np.concatenate((np.full(idx, psd[idx]), psd[idx:]))
+        elif psd.shape[0] > N // 2 + 1:
+            psd = psd[:N // 2 + 1]
+    
+        phases = np.random.rand(N // 2 + 1)
+        height_profile = HeightProfile()
+        height_profile.N = N
+        height_profile.L = L
+        height_profile.s = np.linspace(-L / 2, L / 2, N)
+        height_profile.h = (N / L) * np.fft.irfft(np.sqrt(L * psd) * np.exp(1j * phases * 2 * np.pi),
+                                                                   n=N) / np.sqrt(np.pi)
+        # scaling height_map
+        height_profile.set_hrms(hrms)
+        
+        np.random.seed()
+        
+        return height_profile
+
+
+### just must to be here for generating dfl :_)
+
+def generate_gaussian_dfl(xlamds=1e-9, shape=(51, 51, 100), dgrid=(1e-3, 1e-3, 50e-6), power_rms=(0.1e-3, 0.1e-3, 5e-6),
+                          power_center=(0, 0, None), power_angle=(0, 0), power_waistpos=(0, 0), wavelength=None,
+                          zsep=None, freq_chirp=0, en_pulse=None, power=1e6, **kwargs):
+    """
+    generates RadiationField object
+    narrow-bandwidth, paraxial approximations
+
+    xlamds [m] - central wavelength
+    shape (x,y,z) - shape of field matrix (reversed) to dfl.fld
+    dgrid (x,y,z) [m] - size of field matrix
+    power_rms (x,y,z) [m] - rms size of the radiation distribution (gaussian)
+    power_center (x,y,z) [m] - position of the radiation distribution
+    power_angle (x,y) [rad] - angle of further radiation propagation
+    power_waistpos (x,y) [m] downstrean location of the waist of the beam
+    wavelength [m] - central frequency of the radiation, if different from xlamds
+    zsep (integer) - distance between slices in z as zsep*xlamds
+    freq_chirp dw/dt=[1/fs**2] - requency chirp of the beam around power_center[2]
+    en_pulse, power = total energy or max power of the pulse, use only one
+    """
+
+    start = time.time()
+
+    if dgrid[2] is not None and zsep is not None:
+        if shape[2] == None:
+            shape = (shape[0], shape[1], int(dgrid[2] / xlamds / zsep))
+        else:
+            _logger.error(ind_str + 'dgrid[2] or zsep should be None, since either determines longiduninal grid size')
+
+    _logger.info('generating radiation field of shape (nz,ny,nx): ' + str(shape))
+    if 'energy' in kwargs:
+        _logger.warn(ind_str + 'rename energy to en_pulse, soon arg energy will be deprecated')
+        en_pulse = kwargs.pop('energy', 1)
+
+    dfl = RadiationField((shape[2], shape[1], shape[0]))
+
+    k = 2 * np.pi / xlamds
+
+    dfl.xlamds = xlamds
+    dfl.domain_z = 't'
+    dfl.domain_xy = 's'
+    dfl.dx = dgrid[0] / dfl.Nx()
+    dfl.dy = dgrid[1] / dfl.Ny()
+
+    if dgrid[2] is not None:
+        dz = dgrid[2] / dfl.Nz()
+        zsep = int(dz / xlamds)
+        if zsep == 0:
+            _logger.warning(
+                ind_str + 'dgrid[2]/dfl.Nz() = dz = {}, which is smaller than xlamds = {}. zsep set to 1'.format(dz,
+                                                                                                                 xlamds))
+            zsep = 1
+        dfl.dz = xlamds * zsep
+    elif zsep is not None:
+        dfl.dz = xlamds * zsep
+    else:
+        _logger.error('dgrid[2] or zsep should be not None, since they determine longiduninal grid size')
+
+    rms_x, rms_y, rms_z = power_rms  # intensity rms [m]
+    _logger.debug(ind_str + 'rms sizes = [{}, {}, {}]m (x,y,z)'.format(rms_x, rms_y, rms_z))
+    xp, yp = power_angle
+    x0, y0, z0 = power_center
+    zx, zy = power_waistpos
+
+    if z0 == None:
+        z0 = dfl.Lz() / 2
+
+    xl = np.linspace(-dfl.Lx() / 2, dfl.Lx() / 2, dfl.Nx())
+    yl = np.linspace(-dfl.Ly() / 2, dfl.Ly() / 2, dfl.Ny())
+    zl = np.linspace(0, dfl.Lz(), dfl.Nz())
+    z, y, x = np.meshgrid(zl, yl, xl, indexing='ij')
+
+    qx = 1j * np.pi * (2 * rms_x) ** 2 / xlamds + zx
+    qy = 1j * np.pi * (2 * rms_y) ** 2 / xlamds + zy
+    qz = 1j * np.pi * (2 * rms_z) ** 2 / xlamds
+
+    if wavelength.__class__ in [list, tuple, np.ndarray] and len(wavelength) == 2:
+        domega = 2 * np.pi * speed_of_light * (1 / wavelength[0] - 1 / wavelength[1])
+        dt = (z[-1, 0, 0] - z[0, 0, 0]) / speed_of_light
+        freq_chirp = domega / dt / 1e30 / zsep
+        # freq_chirp = (wavelength[1] - wavelength[0]) / (z[-1,0,0] - z[0,0,0])
+        _logger.debug(ind_str + 'difference wavelengths {} {}'.format(wavelength[0], wavelength[1]))
+        _logger.debug(ind_str + 'difference z {} {}'.format(z[-1, 0, 0], z[0, 0, 0]))
+        _logger.debug(ind_str + 'd omega {}'.format(domega))
+        _logger.debug(ind_str + 'd t     {}'.format(dt))
+        _logger.debug(ind_str + 'calculated chirp {}'.format(freq_chirp))
+        wavelength = np.mean([wavelength[0], wavelength[1]])
+
+    if wavelength == None and xp == 0 and yp == 0:
+        phase_chirp_lin = 0
+    elif wavelength == None:
+        phase_chirp_lin = x * np.sin(xp) + y * np.sin(yp)
+    else:
+        phase_chirp_lin = (z - z0) / dfl.dz * (dfl.xlamds - wavelength) / wavelength * xlamds * zsep + x * np.sin(
+            xp) + y * np.sin(yp)
+
+    if freq_chirp == 0:
+        phase_chirp_quad = 0
+    else:
+        # print(dfl.scale_z() / speed_of_light * 1e15)
+        # phase_chirp_quad = freq_chirp *((z-z0)/dfl.dz*zsep)**2 * xlamds / 2# / pi**2
+        phase_chirp_quad = freq_chirp / (speed_of_light * 1e-15) ** 2 * (zl - z0) ** 2 * dfl.xlamds  # / pi**2
+        # print(phase_chirp_quad.shape)
+
+    # if qz == 0 or qz == None:
+    #     dfl.fld = np.exp(-1j * k * ( (x-x0)**2/2/qx + (y-y0)**2/2/qy - phase_chirp_lin + phase_chirp_quad ) )
+    # else:
+    arg = np.zeros_like(z).astype('complex128')
+    if qx != 0:
+        arg += (x - x0) ** 2 / 2 / qx
+    if qy != 0:
+        arg += (y - y0) ** 2 / 2 / qy
+    if abs(qz) == 0:
+        idx = abs(zl - z0).argmin()
+        zz = -1j * np.ones_like(arg)
+        zz[idx, :, :] = 0
+        arg += zz
+    else:
+        arg += (z - z0) ** 2 / 2 / qz
+        # print(zz[:,25,25])
+
+    if np.size(phase_chirp_lin) > 1:
+        arg -= phase_chirp_lin
+    if np.size(phase_chirp_quad) > 1:
+        arg += phase_chirp_quad[:, np.newaxis, np.newaxis]
+    dfl.fld = np.exp(-1j * k * arg)  # - (grid[0]-z0)**2/qz
+    # dfl.fld = np.exp(-1j * k * ( (x-x0)**2/2/qx + (y-y0)**2/2/qy + (z-z0)**2/2/qz - phase_chirp_lin + phase_chirp_quad) ) #  - (grid[0]-z0)**2/qz
+
+    if en_pulse != None and power == None:
+        dfl.fld *= np.sqrt(en_pulse / dfl.E())
+    elif en_pulse == None and power != None:
+        dfl.fld *= np.sqrt(power / np.amax(dfl.int_z()))
+    else:
+        _logger.error('Either en_pulse or power should be defined')
+        raise ValueError('Either en_pulse or power should be defined')
+
+    dfl.filePath = ''
+
+    t_func = time.time() - start
+    _logger.debug(ind_str + 'done in %.2f sec' % (t_func))
+
+    return dfl
+
+
+def imitate_sase_dfl(xlamds, rho=2e-4, seed=None, **kwargs):
+    """
+    imitation of SASE radiation in 3D
+
+    xlamds - wavelength of the substracted fast-varying component
+    rho - half of the expected FEL bandwidth
+    **kwargs identical to generate_dfl()
+
+    returns RadiationField object
+    """
+
+    _logger.info('imitating SASE radiation')
+    if kwargs.get('wavelength', None) is not None:
+        E0 = h_eV_s * speed_of_light / kwargs.pop('wavelength')
+        _logger.debug(ind_str + 'using wavelength')
+    else:
+        E0 = h_eV_s * speed_of_light / xlamds
+        _logger.debug(ind_str + 'using xlamds')
+    dE = E0 * 2 * rho
+    _logger.debug(ind_str + 'E0 = {}'.format(E0))
+    _logger.debug(ind_str + 'dE = {}'.format(dE))
+    dfl = generate_gaussian_dfl(xlamds, **kwargs)
+
+    _logger.debug(ind_str + 'dfl.shape = {}'.format(dfl.shape()))
+    td_scale = dfl.scale_z()
+    _logger.debug(ind_str + 'time domain range = [{},  {}]m'.format(td_scale[0], td_scale[-1]))
+
+    dk = 2 * np.pi / dfl.Lz()
+    k = 2 * np.pi / dfl.xlamds
+    fd_scale_ev = h_eV_s * speed_of_light * (
+        np.linspace(k - dk / 2 * dfl.Nz(), k + dk / 2 * dfl.Nz(), dfl.Nz())) / 2 / np.pi
+    fd_env = np.exp(-(fd_scale_ev - E0) ** 2 / 2 / (dE) ** 2)
+    _logger.debug(ind_str + 'frequency domain range = [{},  {}]eV'.format(fd_scale_ev[0], fd_scale_ev[-1]))
+    
+    for key in imitate_1d_sase_like.__code__.co_varnames:
+        kwargs.pop(key, None)
+        
+    _, td_envelope, _, _ = imitate_1d_sase_like(td_scale=td_scale, td_env=np.ones_like(td_scale), fd_scale=fd_scale_ev,
+                                                fd_env=fd_env, td_phase=None, fd_phase=None, phen0=None, en_pulse=1,
+                                                fit_scale='td', n_events=1, seed=seed, **kwargs)
+
+    dfl.fld *= td_envelope[:, :, np.newaxis]
+
+    return dfl
+
+def calc_ph_sp_dens(spec, freq_ev, n_photons, spec_squared=1):
+    """
+    calculates number of photons per electronvolt
+    """
+    # _logger.debug('spec.shape = {}'.format(spec.shape))
+    if spec.ndim == 1:
+        axis = 0
+    else:
+        if spec.shape[0] == freq_ev.shape[0]:
+            spec = spec.T
+        axis = 1
+        #     axis=0
+        # elif spec.shape[1] == freq_ev.shape[0]:
+        #     axis=1
+        # else:
+        #     raise ValueError('operands could not be broadcast together with shapes ', spec.shape, ' and ', freq_ev.shape)
+    # _logger.debug('spec.shape = {}'.format(spec.shape))
+
+    if spec_squared:
+        spec_sum = np.trapz(spec, x=freq_ev, axis=axis)
+    else:
+        spec_sum = np.trapz(abs(spec) ** 2, x=freq_ev, axis=axis)
+
+    if np.size(spec_sum) == 1:
+        if spec_sum == 0:  # avoid division by zero
+            spec_sum = np.inf
+    else:
+        spec_sum[spec_sum == 0] = np.inf  # avoid division by zero
+
+    if spec_squared:
+        norm_factor = n_photons / spec_sum
+    else:
+        norm_factor = np.sqrt(n_photons / spec_sum)
+
+    if spec.ndim == 2:
+        norm_factor = norm_factor[:, np.newaxis]
+    # _logger.debug('spec.shape = {}'.format(spec.shape))
+    # _logger.debug('norm_factor.shape = {}'.format(norm_factor.shape))
+    spec = spec * norm_factor
+    if axis == 1:
+        spec = spec.T
+    # _logger.debug('spec.shape = {}'.format(spec.shape))
+    return spec
+
+def imitate_1d_sase_like(td_scale, td_env, fd_scale, fd_env, td_phase=None, fd_phase=None, phen0=None, en_pulse=None,
+                         fit_scale='td', n_events=1, **kwargs):
+    """
+    Models FEL pulse(s) based on Gaussian statistics
+    td_scale - scale of the pulse on time domain [m]
+    td_env - expected pulse envelope in time domain [W]
+    fd_scale - scale of the pulse in frequency domain [eV]
+    fd_env - expected pulse envelope in frequency domain [a.u.]
+    td_phase - additional phase chirp to be added in time domain
+    fd_phase - additional phase chirp to be added in frequency domain
+    phen0 - sampling wavelength expressed in photon energy [eV]
+    en_pulse - expected average energy of the pulses [J]
+    fit_scale - defines the scale in which outputs should be returned:
+        'td' - time domain scale td_scale is used for the outputs, frequency domain phase and envelope will be re-interpolated
+        'fd' - frequency domain scale fd_scale is used for the outputs, time domain phase and envelope will be re-interpolated
+    n_events - number of spectra to be generated
+
+    returns tuple of 4 arguments: (ph_en, fd, s, td)
+    fd_scale - colunm of photon energies in eV
+    fd - matrix of radiation in frequency domain with shape, normalized such that np.sum(abs(fd)**2) is photon spectral density, i.e: np.sum(abs(fd)**2)*fd_scale = N_photons
+    td - matrix of radiation in time domain, normalized such that abs(td)**2 = radiation_power in [w]
+    """
+
+    _logger.info('generating 1d radiation field imitating SASE')
+    
+    seed = kwargs.get('seed', None)
+    if seed is not None:
+        np.random.seed(seed)
+
+    if fit_scale == 'td':
+
+        n_points = len(td_scale)
+        s = td_scale
+        Ds = (td_scale[-1] - td_scale[0])
+        ds = Ds / n_points
+
+        td = np.random.randn(n_points, n_events) + 1j * np.random.randn(n_points, n_events)
+        td *= np.sqrt(td_env[:, np.newaxis])
+        fd = np.fft.ifftshift(np.fft.fft(np.fft.fftshift(td, axes=0), axis=0), axes=0)
+        # fd = np.fft.ifft(td, axis=0)
+        # fd = np.fft.fftshift(fd, axes=0)
+
+        if phen0 is not None:
+            e_0 = phen0
+        else:
+            e_0 = np.mean(fd_scale)
+
+        # internal interpolated values
+        fd_scale_i = h_eV_s * np.fft.fftfreq(n_points, d=(
+                ds / speed_of_light)) + e_0  # internal freq.domain scale based on td_scale
+        fd_scale_i = np.fft.fftshift(fd_scale_i, axes=0)
+        fd_env_i = np.interp(fd_scale_i, fd_scale, fd_env, right=0, left=0)
+
+        if fd_phase is None:
+            fd_phase_i = np.zeros_like(fd_env_i)
+        else:
+            fd_phase_i = np.interp(fd_scale_i, fd_scale, fd_phase, right=0, left=0)
+
+        fd *= np.sqrt(fd_env_i[:, np.newaxis]) * np.exp(1j * fd_phase_i[:, np.newaxis])
+
+        # td = np.fft.ifftshift(fd, axes=0)
+        # td = np.fft.fft(td, axis=0)
+        td = np.fft.ifftshift(np.fft.ifft(np.fft.fftshift(fd, axes=0), axis=0), axes=0)
+
+        td_scale_i = td_scale
+
+    elif fit_scale == 'fd':
+
+        n_points = len(fd_scale)
+        Df = abs(fd_scale[-1] - fd_scale[0]) / h_eV_s
+        df = Df / n_points
+
+        fd = np.random.randn(n_points, n_events) + 1j * np.random.randn(n_points, n_events)
+        fd *= np.sqrt(fd_env[:, np.newaxis])
+        td = np.fft.ifftshift(np.fft.ifft(np.fft.fftshift(fd, axes=0), axis=0), axes=0)
+
+        td_scale_i = np.fft.fftfreq(n_points, d=df) * speed_of_light
+        td_scale_i = np.fft.fftshift(td_scale_i, axes=0)
+        td_scale_i -= np.amin(td_scale_i)
+        td_env_i = np.interp(td_scale_i, td_scale, td_env, right=0, left=0)
+
+        if td_phase is None:
+            td_phase_i = np.zeros_like(td_env_i)
+        else:
+            td_phase_i = np.interp(td_scale_i, td_scale, td_phase, right=0, left=0)
+
+        td *= np.sqrt(td_env_i[:, np.newaxis]) * np.exp(1j * td_phase_i[:, np.newaxis])
+
+        fd = np.fft.ifftshift(np.fft.fft(np.fft.fftshift(td, axes=0), axis=0), axes=0)
+
+        fd_scale_i = fd_scale
+
+    else:
+        raise ValueError('fit_scale should be either "td" of "fd"')
+
+    # normalization for pulse energy
+    if en_pulse == None:
+        _logger.debug(ind_str + 'no en_pulse provided, calculating from integral of td_env')
+        en_pulse = np.trapz(td_env, td_scale / speed_of_light)
+
+    pulse_energies = np.trapz(abs(td) ** 2, td_scale_i / speed_of_light, axis=0)
+    scale_coeff = en_pulse / np.mean(pulse_energies)
+    td *= np.sqrt(scale_coeff)
+
+    # normalization for photon spectral density
+    spec = np.mean(np.abs(fd) ** 2, axis=1)
+    spec_center = np.sum(spec * fd_scale_i) / np.sum(spec)
+
+    n_photons = pulse_energies * scale_coeff / q_e / spec_center
+    fd = calc_ph_sp_dens(fd, fd_scale_i, n_photons, spec_squared=0)
+    td_scale, fd_scale = td_scale_i, fd_scale_i
+
+    np.random.seed()
+
+    return (td_scale, td, fd_scale, fd)
+
+
+def imitate_1d_sase(spec_center=500, spec_res=0.01, spec_width=2.5, spec_range=(None, None), pulse_length=6,
+                    en_pulse=1e-3, flattop=0, n_events=1, spec_extend=5, **kwargs):
+    """
+    Models FEL pulse(s) based on Gaussian statistics
+    spec_center - central photon energy in eV
+    spec_res - spectral resolution in eV
+    spec_width - width of spectrum in eV (fwhm of E**2)
+    spec_range = (E1, E2) - energy range of the spectrum. If not defined, spec_range = (spec_center - spec_width * spec_extend, spec_center + spec_width * spec_extend)
+    pulse_length - longitudinal size of the pulse in um (fwhm of E**2)
+    en_pulse - expected average energy of the pulses in Joules
+    flattop - if true, flat-top pulse in time domain is generated with length 'pulse_length' in um
+    n_events - number of spectra to be generated
+
+    return tuple of 4 arguments: (s, td, ph_en, fd)
+    ph_en - colunm of photon energies in eV with size (spec_range[2]-spec_range[1])/spec_res
+    fd - matrix of radiation in frequency domain with shape ((spec_range[2]-spec_range[1])/spec_res, n_events), normalized such that np.sum(abs(fd)**2) is photon spectral density, i.e: np.sum(abs(fd)**2)*spec_res = N_photons
+    s - colunm of longitudinal positions along the pulse in yime domain in um
+    td - matrix of radiation in time domain with shape ((spec_range[2]-spec_range[1])/spec_res, n_events), normalized such that abs(td)**2 = radiation_power
+    """
+
+    if spec_range == (None, None):
+        spec_range = (spec_center - spec_width * spec_extend, spec_center + spec_width * spec_extend)
+    elif spec_center == None:
+        spec_center = (spec_range[1] + spec_range[0]) / 2
+
+    pulse_length_sigm = pulse_length / (2 * np.sqrt(2 * np.log(2)))
+    spec_width_sigm = spec_width / (2 * np.sqrt(2 * np.log(2)))
+
+    fd_scale = np.arange(spec_range[0], spec_range[1], spec_res)
+    n_points = len(fd_scale)
+    _logger.debug(ind_str + 'N_points * N_events = %i * %i' % (n_points, n_events))
+
+    fd_env = np.exp(-(fd_scale - spec_center) ** 2 / 2 / spec_width_sigm ** 2)
+    td_scale = np.linspace(0, 2 * np.pi / (fd_scale[1] - fd_scale[0]) * hr_eV_s * speed_of_light, n_points)
+
+    if flattop:
+        td_env = np.zeros_like(td_scale)
+        il = find_nearest_idx(td_scale, np.mean(td_scale) - pulse_length * 1e-6 / 2)
+        ir = find_nearest_idx(td_scale, np.mean(td_scale) + pulse_length * 1e-6 / 2)
+        td_env[il:ir] = 1
+    else:
+        s0 = np.mean(td_scale)
+        td_env = np.exp(-(td_scale - s0) ** 2 / 2 / (pulse_length_sigm * 1e-6) ** 2)
+
+    result = imitate_1d_sase_like(td_scale, td_env, fd_scale, fd_env, phen0=spec_center, en_pulse=en_pulse,
+                                  fit_scale='fd', n_events=n_events, **kwargs)
+
+    return result
+    
+def dfldomain_check(domains, both_req=False):
+    err = ValueError(
+        'domains should be a string with one or two letters from ("t" or "f") and ("s" or "k"), not {}'.format(
+            str(domains)))
+
+    # if type(domains) is not str:
+    #     raise err
+    if len(domains) < 1 or len(domains) > 2:
+        raise err
+    if len(domains) < 2 and both_req == True:
+        raise ValueError('please provide both domains, e.g. "ts" "fs" "tk" "fk"')
+
+    domains_avail = ['t', 'f', 's', 'k']
+    for letter in domains:
+        if letter not in domains_avail:
+            raise err
+
+    if len(domains) == 2:
+        D = [['t', 'f'], ['s', 'k']]
+        for d in D:
+            if domains[0] in d and domains[1] in d:
+                raise err
+
+        """
+        tranfers radiation to specified domains
+        *domains is a string with one or two letters: 
+            ("t" or "f") and ("s" or "k")
+        where 
+            't' (time); 'f' (frequency); 's' (space); 'k' (inverse space); 
+        e.g.
+            't'; 'f'; 's'; 'k'; 'ts'; 'fs'; 'tk'; 'fk'
+        order does not matter
+        
+        **kwargs are passed down to self.fft_z and self.fft_xy
+        """                
+
+
+
+
+
diff --git a/ocelot/optics/wave.py b/ocelot/optics/wave.py
index 7f821321..1fff473c 100644
--- a/ocelot/optics/wave.py
+++ b/ocelot/optics/wave.py
@@ -8,6 +8,7 @@
 from math import factorial
 from numpy import inf, complex128, complex64
 import scipy
+import scipy.special as sc
 import numpy.fft as fft
 from copy import deepcopy
 import time
@@ -15,7 +16,8 @@
 
 # from ocelot.optics.elements import *
 from ocelot.common.globals import *
-from ocelot.common.math_op import find_nearest_idx, fwhm, std_moment, bin_scale, bin_array, mut_coh_func
+from ocelot.common.math_op import find_nearest_idx, fwhm, std_moment, bin_scale, bin_array, mut_coh_func, mprefix
+from ocelot.rad.undulator_params import lambda2eV, eV2lambda, k2lambda, lambda2k, k2angle, angle2k
 from ocelot.common.py_func import filename_from_path
 # from ocelot.optics.utils import calc_ph_sp_dens
 # from ocelot.adaptors.genesis import *
@@ -361,6 +363,7 @@ def fft_z(self, method='mp', nthread=multiprocessing.cpu_count(),
             method = 'np'
         
         if orig_domain == 't':
+            self.fld = np.fft.ifftshift(self.fld, 0)
             if method == 'mp' and fftw_avail:
                 fft_exec = pyfftw.builders.fft(self.fld, axis=0, overwrite_input=True, planner_effort='FFTW_ESTIMATE',
                                                threads=nthread, auto_align_input=False, auto_contiguous=False,
@@ -370,11 +373,11 @@ def fft_z(self, method='mp', nthread=multiprocessing.cpu_count(),
                 self.fld = np.fft.fft(self.fld, axis=0)
             # else:
             #     raise ValueError('fft method should be "np" or "mp"')
-            self.fld = np.fft.ifftshift(self.fld, 0)
+            self.fld = np.fft.fftshift(self.fld, 0)
             self.fld /= np.sqrt(self.Nz())
             self.domain_z = 'f'
         elif orig_domain == 'f':
-            self.fld = np.fft.fftshift(self.fld, 0)
+            self.fld = np.fft.ifftshift(self.fld, 0)
             if method == 'mp' and fftw_avail:
                 fft_exec = pyfftw.builders.ifft(self.fld, axis=0, overwrite_input=True, planner_effort='FFTW_ESTIMATE',
                                                 threads=nthread, auto_align_input=False, auto_contiguous=False,
@@ -385,6 +388,7 @@ def fft_z(self, method='mp', nthread=multiprocessing.cpu_count(),
                 
                 # else:
                 # raise ValueError("fft method should be 'np' or 'mp'")
+            self.fld = np.fft.fftshift(self.fld, 0)
             self.fld *= np.sqrt(self.Nz())
             self.domain_z = 't'
         else:
@@ -406,6 +410,7 @@ def fft_xy(self, method='mp', nthread=multiprocessing.cpu_count(),
             method = 'np'
         
         if domain_orig == 's':
+            self.fld = np.fft.ifftshift(self.fld, axes=(1, 2))
             if method == 'mp' and fftw_avail:
                 fft_exec = pyfftw.builders.fft2(self.fld, axes=(1, 2), overwrite_input=False,
                                                 planner_effort='FFTW_ESTIMATE', threads=nthread, auto_align_input=False,
@@ -427,6 +432,7 @@ def fft_xy(self, method='mp', nthread=multiprocessing.cpu_count(),
                 self.fld = fft_exec()
             else:
                 self.fld = np.fft.ifft2(self.fld, axes=(1, 2))
+            self.fld = np.fft.fftshift(self.fld, axes=(1, 2))
             # else:
             #     raise ValueError("fft method should be 'np' or 'mp'")
             self.fld *= np.sqrt(self.Nx() * self.Ny())
@@ -620,6 +626,8 @@ def prop_m(self, z, m=1, fine=1, return_result=0, return_orig_domains=1, **kwarg
     def mut_coh_func(self, norm=1, jit=1):
         '''
         calculates mutual coherence function
+        see Goodman Statistical optics EQs 5.2-7, 5.2-11
+        returns matrix [y,x,y',x']
         consider downsampling the field first
         '''
         if jit:
@@ -634,6 +642,42 @@ def mut_coh_func(self, norm=1, jit=1):
                 J /= (I[:, :, np.newaxis, np.newaxis] * I[np.newaxis, np.newaxis, :, :])
         return J
     
+    def mut_coh_func_c(self, center=(0,0), norm=1):
+        '''
+        Function to calculate mutual coherence function cenetered at xy position
+    
+        Parameters
+        ----------
+        center_xy : tuple, optional
+            DESCRIPTION. 
+            point with respect to which correlation is calculated
+            The default is (0,0) (center)
+            accepts values either in [m] if domain=='s'
+                               or in [rad] if domain=='k'
+        norm : TYPE, optional
+            DESCRIPTION. 
+            The default is 1.
+            flag of normalization by intensity
+        Returns
+        -------
+        J : TYPE
+            mutual coherence function matrix [ny, nx]
+        '''
+    
+        scalex = self.scale_x()
+        scaley = self.scale_y()
+        
+        ix = find_nearest_idx(scalex, center[0])
+        iy = find_nearest_idx(scaley, center[1])
+        
+        dfl1 = self.fld[:, iy, ix, np.newaxis, np.newaxis].conjugate()
+        dfl2 = self.fld[:, :, :]
+        J = np.mean(dfl1 * dfl2, axis=0)
+        if norm:
+            I = self.int_xy() / self.Nz()
+            J = J / (I[Nyh, np.newaxis :] * I[:, Nxh, np.newaxis])
+        return J
+    
     def coh(self, jit=0):
         '''
         calculates degree of transverse coherence
@@ -1335,42 +1379,148 @@ class WignerDistribution():
 
     def __init__(self):
         # self.fld=np.array([]) #(z,y,x)
-        self.field = []
-        self.wig = []  # (wav,space)
+        #self.field = [] # 1d array to save space
+        self.field_stat = [0] # list of self.field-like arrays
+        #self.wig = []  # (wav,space)
+        self.wig_stat = [0] # same as wig.wig, but with another dimention hosting different events
         self.s = []  # space scale
-        self.z = None  # position along undulator (if applicable)
-        self.phen = []  # photon energy
-        self.xlamds = 0  # wavelength, [nm]
+        self.k = [] # inverse space scale
+        # self.phen = []  # photon energy
+        self.xlamds = 0  # carrier SVEA wavelength, [nm]
+        self.z = None  # position along undulator (reserved)
+        self.domain = 't'
         self.filePath = ''
-
+    
     @property
-    def freq_lamd(self):
-        return h_eV_s * speed_of_light * 1e9 / self.phen
-
-    @freq_lamd.setter
-    def freq_lamd(self, value):
-        self.phen = h_eV_s * speed_of_light * 1e9 / value
-
-    def power(self):
+    def field(self):
+        return self.field_stat[0]
+    
+    @field.setter
+    def field(self,value):
+        if len(self.field_stat) == 0:
+            self.field_stat[0] = [value]
+        else:
+            self.field_stat[0] = value
+        
+    @property
+    def wig(self):
+        return self.wig_stat[0]
+    
+    @wig.setter
+    def wig(self,value):
+        if len(self.wig_stat) == 0:
+            self.wig_stat[0] = [value]
+        else:
+            self.wig_stat[0] = value
+    
+    def __getitem__(self, i):
+        return self.wig_stat[i]
+    
+    def proj_s(self):
+        # real space projection
         return np.sum(self.wig, axis=0)
-
-    def spectrum(self):
+        
+    def proj_k(self):
+        # inverse space projection
         return np.sum(self.wig, axis=1)
-
-    def energy(self):
-        return np.sum(self.wig) * abs(self.s[1] - self.s[0]) / speed_of_light
-
+    
+    def moment1_k(self):
+        # prevailing tilt (frequency) for every coordinate (time)
+        proj_s = self.proj_s()
+        if np.all(proj_s == 0):
+            return proj_s
+        else:
+            proj_s[proj_s == 0] = np.nan
+            return np.sum(self.wig * self.k[:, np.newaxis], axis=0) / proj_s
+
+    def moment1_s(self):
+        # prevailing coordinate (time) for every tilt (frequency)
+        proj_k = self.proj_k()
+        if np.all(proj_k == 0):
+            return proj_k
+        else:
+            proj_k[proj_k == 0] = np.nan
+            return np.sum(self.wig * self.s[np.newaxis, :], axis=1) / proj_k
+    
+    def moment2_k(self):
+        # instantaneous bandwitdh / ?
+        proj_s = self.power()
+        if np.all(proj_s == 0):
+            return proj_s
+        else:
+            return np.sum(self.wig * (self.k[:, np.newaxis] - self.moment1_k()[np.newaxis, :]) ** 2, axis=0) / proj_s
+    
+    def moment2_s(self):
+        # group duration / ?
+        proj_k = self.proj_k()
+        if np.all(proj_k == 0):
+            return proj_k
+        else:
+            return np.sum(self.wig * (self.s[np.newaxis, :] - self.moment1_s()[:, np.newaxis]) ** 2, axis=1) / proj_k
+    
     def fileName(self):
         return filename_from_path(self.filePath)
-
+    
     def eval(self, method='mp'):
+        n_events = len(self.field_stat)
+        _logger.info('evaluating wigner distribution from {:} event(s)'.format(n_events))
         # from ocelot.utils.xfel_utils import calc_wigner
         ds = self.s[1] - self.s[0]
-        self.wig = calc_wigner(self.field, method=method, debug=1)
-        phen = h_eV_s * (np.fft.fftfreq(self.s.size, d=ds / speed_of_light) + speed_of_light / self.xlamds)
-        self.phen = np.fft.fftshift(phen, axes=0)
+        # self.wig = calc_wigner(self.field, method=method, debug=1)
+        # if self.field_stat != []:
+        self.wig_stat = [calc_wigner(field, method=method, debug=1) for field in self.field_stat]
+        if self.domain in ['s', 'x', 'y']:
+            self.k = np.linspace(-np.pi / ds, np.pi / ds, len(self.s))
+        elif self.domain in ['t', 'z']:
+            self.k = 2 * pi / self.xlamds + np.linspace(-np.pi / ds, np.pi / ds, len(self.s))# * len(self.s)
+            #phen = lambda2eV(k2lambda(self.k))
+            #self.phen = phen
+            #phen = h_eV_s * (np.fft.fftfreq(self.s.size, d=ds / speed_of_light) + speed_of_light / self.xlamds)
+            # self.phen = np.fft.fftshift(phen, axes=0)
+        else:
+            raise ValueError()
+            
+    def sum(self):
+        return(np.sum(self.wig))
+        
+    def sum_stat(self):
+        return([np.sum(wig) for wig in self.wig_stat])
         # self.freq_lamd = h_eV_s * speed_of_light * 1e9 / freq_ev
+    
+    def normalize(self):
+        self.wig = self.wig / self.sum()
+        
+    def ensemble_average(self):
+        if np.shape(self.wig_stat)[0]>1:
+            self.wig_stat = [np.sum(self.wig_stat, axis=0)]
 
+
+class WignerDistributionLongitudinal(WignerDistribution):
+    
+    @property
+    def phen(self):
+        # if self.domain not in ['t','z']:
+            # _logger.error('wigner calculated photon energy not in time domain')
+        return lambda2eV(k2lambda(self.k))
+
+    @phen.setter
+    def phen(self, value):
+        # if self.domain not in ['t','z']:
+            # _logger.error('wigner calculated k from photon energy not in time domain')
+        self.k = lambda2k(eV2lambda(value))
+
+    @property
+    def freq_lamd(self):
+        # if self.domain not in ['t','z']:
+            # _logger.error('wigner calculated wavelength not in time domain')
+        return k2lambda(self.k)
+
+    @freq_lamd.setter
+    def freq_lamd(self, value):
+        # if self.domain not in ['t','z']:
+            # _logger.error('wigner calculated k from wavelength not in time domain')
+        self.k = lambda2k(value)
+    
     def inst_freq(self):
         p = self.power()
         if np.all(p == 0):
@@ -1386,7 +1536,7 @@ def group_delay(self):
         else:
             s[s == 0] = np.nan
             return np.sum(self.wig * self.s[np.newaxis, :], axis=1) / s
-
+    
     def inst_bandwidth(self):
         # check, gives strange tilt. physics?
         p = self.power()
@@ -1394,6 +1544,23 @@ def inst_bandwidth(self):
             return p
         else:
             return np.sum(self.wig * (self.phen[:, np.newaxis] - self.inst_freq()[np.newaxis, :]) ** 2, axis=0) / p
+    
+    def power(self):
+        return self.proj_s()
+    
+    def spectrum(self):
+        return self.proj_k()
+        
+    def energy(self):
+        return np.sum(self.wig) * abs(self.s[1] - self.s[0]) / speed_of_light
+
+    
+class WignerDistributionTransverse(WignerDistribution):
+    
+    def theta(self):
+        # if self.domain not in ['x','y','s']:
+            # _logger.error('wigner calculated k from wavelength not in time domain')
+        return k2angle(self.k, self.xlamds)
 
 
 def generate_dfl(*args, **kwargs):
@@ -1420,9 +1587,8 @@ def generate_gaussian_dfl(xlamds=1e-9, shape=(51, 51, 100), dgrid=(1e-3, 1e-3, 5
     freq_chirp dw/dt=[1/fs**2] - requency chirp of the beam around power_center[2]
     en_pulse, power = total energy or max power of the pulse, use only one
     """
-
     start = time.time()
-
+    
     if dgrid[2] is not None and zsep is not None:
         if shape[2] == None:
             shape = (shape[0], shape[1], int(dgrid[2] / xlamds / zsep))
@@ -1582,13 +1748,426 @@ def imitate_sase_dfl(xlamds, rho=2e-4, seed=None, **kwargs):
         kwargs.pop(key, None)
         
     _, td_envelope, _, _ = imitate_1d_sase_like(td_scale=td_scale, td_env=np.ones_like(td_scale), fd_scale=fd_scale_ev,
-                                                fd_env=fd_env, td_phase=None, fd_phase=None, phen0=None, en_pulse=1,
+                                                fd_env=fd_env, td_phase=None, fd_phase=None, phen0=None, en_pulse=1,#TODO: check 
                                                 fit_scale='td', n_events=1, seed=seed, **kwargs)
 
     dfl.fld *= td_envelope[:, :, np.newaxis]
 
     return dfl
 
+def undulator_field_far(theta_x, theta_y, l_x, l_y, eta_x, eta_y, z, L_w, E_ph, phi=False, C=0): 
+    '''
+    Undulator field generator for the far field approximation
+    
+    ### field expressions look at the following article
+    Geloni, Gianluca, et al. "Fourier treatment of near-field synchrotron radiation theory." Optics communications 276.1 (2007): 167-179.
+    ###
+    
+    Parameters
+    ----------
+    theta_x : float
+        grid along x having a shape [Nx, Ny]
+    theta_y : float
+        grid along y having a shape [Nx, Ny]
+    l_x : float
+        random x offset of an electron
+    l_y : float
+        random y offset of the electron
+    eta_x : float
+        random x deflection angle of the electron
+    eta_y : float
+        random y deflection angle of the electron
+    L_w : float, optional
+        Undulator length in meteres
+    E_ph : int, optional
+        Photon energy in eV
+    phi : double. Default is None 
+        longitudinal phase of the electron. If not None -- long beam approximation: fields sum up with a random phase; 
+        if None -- short beam approximation: fields sum up in phase.
+    C : the field detuning from the resonance defined as 2pi/lambda_w * (dw/w_r). The default is 0.
+    Returns
+    -------
+    an array with a shape (Nx, Ny)
+        the field emitted by the electron
+    '''
+    lambda_w = 0.04
+    w = E_ph / hr_eV_s 
+     
+    _logger.debug(ind_str + 'calculating undulator field in the far field approximation')
+    
+    if z != 0: 
+        z_0 = z
+    else: 
+        raise AttributeError('"phi" is bool type ')
+        _logger.error('"z" must not be zero')
+    
+    start_time = time.time()
+    E = -np.sinc(L_w * C / 2 + L_w * w * ((theta_x - (l_x/z_0) - eta_x)**2 + (
+                            theta_y - (l_y/z_0) - eta_y)**2) / 4 /speed_of_light / np.pi) * np.exp(
+                            1j * w  * z_0 * ((theta_x - (l_x/z_0))**2 + (theta_y - (l_y/z_0))**2) / 2 / speed_of_light)
+    if phi != None:
+        _logger.debug(ind_str + 'adding a random phase to the field')
+        E = E * np.exp(1j * phi)
+    
+    _logger.debug(ind_str + 'done in {:.2f} seconds'.format(time.time() - start_time))
+    return E        
+
+def undulator_field_near(x, y, l_x, l_y, eta_x, eta_y, z, L_w, E_ph, phi=None):
+    '''
+    Field generator for near field approximation
+    
+    ### field expressions look at the following article
+    Geloni, Gianluca, et al. "Fourier treatment of near-field synchrotron radiation theory." Optics communications 276.1 (2007): 167-179.
+    ###
+    
+    Parameters
+    ----------
+    x : float
+        grid along x
+    y : float
+        grid along y
+    l_x : float
+        x offset of an electron
+    l_y : float
+        y offset of the electron
+    eta_x : float
+        x deflection angle of the electron
+    eta_y : float
+        y deflection angle of the electron
+    phi : double. Default is None 
+        longitudinal phase of the electron. The default is None -- short beam approximation: fields sum up in phase. 
+        If not None -- long beam approximation: fields sum up with a random phase. 
+
+    Returns
+    -------
+    array with a shape (Nx, Ny)
+        the field emitted by the electron
+
+    '''
+    w = E_ph / hr_eV_s 
+
+    if z != 0: 
+        z_0 = z
+    else: 
+        raise AttributeError('"phi" is bool type ')
+        _logger.error('"z" must not be zero')
+   
+    _logger.debug('calculating undulator field in the near field approximation')
+    start_time = time.time() 
+    
+    E = (sc.expi(1j * w * ((x - l_x - z_0*eta_x)**2 + (y - l_y - z_0*eta_y)**2) / (2 * z_0 * speed_of_light - L_w*speed_of_light)) - sc.expi(
+        1j * w * ((x - l_x - z_0*eta_x)**2 + (y - l_y - z_0*eta_y)**2) / (2 * z_0 * speed_of_light + L_w*speed_of_light))) * np.exp(
+            1j * w * (((x - l_x)**2 + (y - l_y)**2) - (x - l_x - z_0*eta_x)**2 - (y  - l_y - z_0*eta_y)**2) / 2 / speed_of_light / z_0)  
+    
+    # the field has a singularity at r = 0 and z_0 = L_w
+    ### this block is for excluding nan value
+    _logger.debug(ind_str + 'looking for None value because of features at r = 0 and z_0 = L_w, may appear for filament beams')
+    none_indx = np.where(np.isnan(E))
+    if not none_indx:    
+        _logger.WARNING(ind_str + "none_indx = {}".format(none_indx))
+        avr = E[(none_indx[0] - 1)[0]:(none_indx[0] + 2)[0],(none_indx[1] - 1)[0]:(none_indx[1] + 2)[0]]
+        avr = np.average(avr[~np.isnan(avr)])
+        E[none_indx] = avr
+        _logger.debug(ind_str + 'nan value found')
+    else:
+        _logger.debug(ind_str + 'no nan value found')
+    ###
+    
+    if phi != None:
+        _logger.debug(ind_str + 'adding a random phase to the field')
+        _logger.debug(ind_str + 'done in {:.2f} seconds'.format(time.time() - start_time))
+        return E * np.exp(1j * phi)
+    else:
+        _logger.debug(ind_str + 'done in {:.2f} seconds'.format(time.time() - start_time))
+        return E
+
+def dfl_gen_undulator_sp(dfl, z, L_w, E_ph, N_e=1, sig_x=0, sig_y=0, sig_xp=0, sig_yp=0, C=0, approximation='far_field', mode='incoh', seed=None):
+    
+    """  
+    SRW-like Undulator radiation generator - single particle radiation is propagated through the optical system
+    
+    Parameters
+    ----------
+    dfl : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+        
+        Transverse dfl.fld.shape defines the field dimension -- (Nx, Ny).
+        
+        Returned dfl.fld represents a simulation where longitudibnal scale is N_e single electron fields, 
+        each field has its own amplitude and the phase; and propagets seperatly. 
+        
+        After propagation intesities should be summed up to find the resulting field 
+    
+    z : float
+        Distance from source at which the field is calculated
+    N_e : int, optional
+        Number of macro particles in an electron bunch. The default is 1.
+    L_w : float, optional
+        Undulator length in meteres
+    E_ph : int, optional
+        Photon energy in eV
+    sig_x : float, optional
+        r.m.s. of the x electron offset assuming Gaussian distribution. The default is 0.
+    sig_y : float, optional
+        r.m.s. of the y electron offset assuming Gaussian distribution. The default is 0.
+    sig_xp : float, optional
+        r.m.s. of the x electron deflection assuming Gaussian distribution. The default is 0.
+    sig_yp : float, optional
+        r.m.s. of the y electron deflection assuming Gaussian distribution. The default is 0.
+    C: float
+        the field detuning from the resonance defined as 2pi/lambda_w * (dw/w_r). The default is 0.
+    approximation : str, optional
+        Used approximation to calculate the field ('near or farfield'). The default is 'far_field'.
+    mode : str, optional
+       A mode to sum up the field. For the SRW generator physical meaning has only incoherent addition of fields. The default is 'incoh'.
+    seed : int, optional
+        A seed for the random generator. The default is None.
+
+    Returns
+    -------
+    dfl : RadiationField object with dfl.shape = (N_e, dfl.Ny(), dfl.Nx())
+    """
+        
+    _logger.info('Calculating undulator field with SRW-like approach')
+    _logger.info(ind_str + 'used approximation is ' + approximation.replace('_', ' '))
+
+    start_time = time.time()
+
+    if approximation == 'near_field':
+        dfl.to_domain(domains='sf', indexing='ij') 
+        x = dfl.scale_kx()
+        y = dfl.scale_ky()
+        x, y = np.meshgrid(x, y)    
+    elif approximation == 'far_field':
+        dfl.to_domain(domains='sf', indexing='ij') 
+        kx = dfl.scale_x()/z
+        ky = dfl.scale_y()/z
+        theta_x, theta_y  = np.meshgrid(kx, ky)
+    else: 
+        _logger.error(ind_str + '"approximation" must be whether "near_field" of "far_field"')
+        raise AttributeError('"approximation" must be whether "near_field" of "far_field"')
+
+    if seed != None:
+        random.seed(seed)
+        _logger.debug(ind_str + 'seed is {}'.format(seed))
+    
+    l_x   = np.random.normal(0, sig_x, (N_e))
+    eta_x = np.random.normal(0, sig_xp, (N_e))
+    l_y   = np.random.normal(0, sig_y, (N_e))
+    eta_y = np.random.normal(0, sig_yp, (N_e))
+    phi = np.random.uniform(low=0, high=2*np.pi, size=N_e)
+
+    if C != 0:
+        _logger.warning(ind_str + 'resonance detuning C has not implemented for the near field calculations')
+    
+    E_list = []
+    i=0
+    for l_xi, l_yi, eta_xi, eta_yi, phi_i in zip(l_x, l_y, eta_x, eta_y, phi):
+        if approximation == 'far_field':
+            if mode == 'incoh':
+                E = undulator_field_far(theta_x, theta_y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph, phi=phi_i, C=C)
+        elif approximation == 'near_field':
+            if mode == 'incoh':
+                E = undulator_field_near(x, y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph, phi=phi_i)
+        else: 
+            _logger.error(ind_str + 'attribute "method" must be "far_field" or "near_field"')
+            raise AttributeError('attribute "method" must be "far_field" or "near_field"') 
+        E_list.append(E)     
+        i = i + 1
+        _logger.info(ind_str + 'fields simulated = {0} out of {1}'.format(i, N_e))
+    
+    E_list = np.array(E_list)
+    dfl.fld = E_list
+    
+    _logger.debug(ind_str + 'undulator field calculated in {:.2f} seconds'.format(time.time() - start_time))
+    _logger.info(ind_str + 'done')
+
+    return dfl
+
+def dfl_gen_undulator_mp(dfl, z, L_w, E_ph, N_b=1, N_e=1, sig_x=0, sig_y=0, sig_xp=0, sig_yp=0, C=0, approximation='far_field', mode='incoh', seed=None):
+    
+    """  
+    Multiple particle Undulator radiation generator - fields from numerous macroparticles is added and propagated as one
+    
+    Parameters
+    ----------
+    dfl : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+        
+        Transverse dfl.fld.shape defines the field dimension -- dfl.shape = (N_e, dfl.Ny(), dfl.Nx())
+        
+        Returned dfl.fld represents a simulation where eahc longitudinal slice is a statistical realization of a field from N_e macro electrons, 
+        each realization has its own amplitude and phase; and propagets seperatly. 
+        
+        After propagation of the realizations the intensities should be summed up to find the resulting field.
+    
+    z : float
+        Distance at which calculate the field
+    N_b : int, optional
+        Number of realizations to generate. The default is 1.
+    N_e : int, optional
+        Number of macro electrons in an electron bunch. The default is 1.
+    L_w : float, optional
+        Undulator length in meteres
+    E_ph : int, optional
+        Photon energy in eV
+    sig_x : float, optional
+        r.m.s. of the x electron offset for the gaussian distribution. The default is 0.
+    sig_y : float, optional
+        r.m.s. of the y electron offset for the gaussian distribution. The default is 0.
+    sig_xp : float, optional
+        r.m.s. of the x electron deflection for the gaussian distribution. The default is 0.
+    sig_yp : float, optional
+        r.m.s. of the y electron deflection for the gaussian distribution. The default is 0.
+    C: float
+        the field detuning from the resonance defined as 2pi/lambda_w * (dw/w_r). The default is 0. 
+    approximation : str, optional
+        Used approximation to culculate the field ('near or farfield'). The default is 'far_field'.
+    mode : str, optional
+       A mode to sum up the field.
+    seed : int, optional
+        A seed for the random generator. The default is None.
+
+    Returns
+    -------
+    dfl : RadiationField object
+    """
+    _logger.info(ind_str + 'Calculating undulator field with Monte Carlo method...')
+    _logger.info(ind_str + 'used approximation is ' + approximation.replace('_', ' '))
+
+    start_time = time.time()
+
+    if approximation == 'near_field':
+        dfl.to_domain(domains='sf', indexing='ij') 
+        x = dfl.scale_kx()
+        y = dfl.scale_ky()
+        x, y = np.meshgrid(x, y)    
+    elif approximation == 'far_field':
+        dfl.to_domain(domains='sf', indexing='ij') 
+        kx = dfl.scale_x()/z
+        ky = dfl.scale_y()/z
+        theta_x, theta_y  = np.meshgrid(kx, ky)
+    else: 
+        _logger.error(ind_str + '"approximation" must be whether "near_field" of "far_field"')
+        raise AttributeError('"approximation" must be whether "near_field" of "far_field"')
+  
+    if seed != None:
+        random.seed(seed)
+        _logger.info('seed is {}'.format(seed))
+    
+    if C != 0:
+        _logger.warning(ind_str + 'resonance detuning C has not implemented for the near field calculations')
+
+    E_list = []   
+    for bunch in range(N_b):
+        l_x   = np.random.normal(0, sig_x, (N_e))
+        eta_x = np.random.normal(0, sig_xp, (N_e))
+        l_y   = np.random.normal(0, sig_y, (N_e))
+        eta_y = np.random.normal(0, sig_yp, (N_e))
+        phi = np.random.uniform(low=0, high=2*np.pi, size=N_e)
+        
+        E = np.zeros((dfl.shape()[1], dfl.shape()[2]))
+        i=0
+        for l_xi, l_yi, eta_xi, eta_yi, phi_i in zip(l_x, l_y, eta_x, eta_y, phi):
+            if approximation == 'far_field':
+                if mode == 'incoh':
+                    E = E + undulator_field_far(theta_x, theta_y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph, phi=phi_i, C=C)   
+                elif mode == 'coh':
+                    E = E + undulator_field_far(theta_x, theta_y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph, C=C)
+            elif approximation == 'near_field':
+                if mode == 'incoh':
+                    E = E + undulator_field_near(x, y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph, phi=phi_i)
+                elif mode == 'coh':
+                    E = E + undulator_field_near(x, y, l_xi, l_yi, eta_xi, eta_yi, z, L_w=L_w, E_ph=E_ph)
+            else: 
+                _logger.error(ind_str + 'attribute "method" must be "far_field" or "near_field"')
+                raise AttributeError('attribute "method" must be "far_field" or "near_field"')
+            
+            if N_b == 1:
+                i = i + 1
+                _logger.info(ind_str + 'electrons simulated = {0} out of {1}'.format(i, N_e))
+        
+        E = E/N_e
+        E_list.append(E)
+        _logger.info(ind_str + 'realizations number = {0} out of {1}'.format(bunch + 1, N_b))
+    
+    E_list = np.array(E_list)
+    dfl.fld = E_list
+
+    _logger.info(ind_str + 'undulator field calculated in {:.2f} seconds'.format(time.time() - start_time))
+
+    return dfl
+
+def dfl_gen_undulator_serval(dfl, L_w, sig_x=0, sig_y=0, sig_xp=0, sig_yp=0, k_support ='intensity', s_support='intensity', showfig=False, seed=None):
+    
+    _logger.info('Generating undulator field with SERVAL algorithm')
+    w_0 = 2*np.pi * speed_of_light / dfl.xlamds
+    
+    if showfig:
+        plot_dfl(dfl, line_off_xy = False, fig_name = '1-X_noise')
+    
+    dfl.to_domain('sf')
+    
+    x, y = np.meshgrid(dfl.scale_x(), dfl.scale_y())#, indexing='ij')
+    
+    mask_xy_ebeam = np.exp(- x**2 / 4 / sig_x**2 - y**2 / 4 / sig_y**2) # 4 because amplitude, not intensity
+    mask_xy_ebeam /= np.sum(mask_xy_ebeam)
+    mask_xy_radiation = 1j*(np.pi - 2*scipy.special.sici(w_0*(x**2 + y**2)/speed_of_light/L_w)[0])
+
+    if s_support == 'intensity':
+        _logger.info(ind_str +'s_support == "intensity"')
+        mask_xy = scipy.signal.fftconvolve(mask_xy_radiation**2, mask_xy_ebeam**2, mode='same')
+        mask_xy = np.sqrt(mask_xy)
+    elif s_support == 'amplitude':
+        _logger.info(ind_str +'s_support == "amplitude"')
+        mask_xy = scipy.signal.fftconvolve(mask_xy_radiation, mask_xy_ebeam, mode='same')
+    elif s_support == '"beam':
+        _logger.info(ind_str +'s_support == "beam"')
+        mask_xy = mask_xy_ebeam
+    else:
+        raise ValueError('k_support should be either "intensity", "amplitude" or "beam"')
+
+    _logger.info(ind_str +'Multiplying by real space mask')
+    dfl.fld *= mask_xy
+    # dfl.fld *= np.sqrt(mask_xy)
+    _logger.info(2*ind_str +'done')
+
+    if showfig:
+        plot_dfl(dfl, domains='s', line_off_xy = False, fig_name = '2-X_e-beam-size')
+        plot_dfl(dfl, domains='k', line_off_xy = False, fig_name = '2-X_e-beam-size')
+                
+    dfl.to_domain('kf')
+
+    k_x, k_y = np.meshgrid(dfl.scale_x(), dfl.scale_y())
+    mask_kxky_ebeam = np.exp(-k_y**2 / 4 / sig_yp**2 - k_x**2 / 4 / sig_xp**2 ) # 4 because amplitude, not intensity
+    mask_kxky_ebeam /= np.sum(mask_kxky_ebeam)
+    mask_kxky_radiation = np.sinc(w_0 * L_w * (k_x**2 + k_y**2) / 4 / speed_of_light / np.pi)# Geloni2018 Eq.3, domega/omega = 2dgamma/gamma, divided by pi due to np.sinc definition
+
+    if k_support == 'intensity':
+        _logger.info(ind_str +'k_support == "intensity"')
+        mask_kxky = scipy.signal.fftconvolve(mask_kxky_ebeam**2, mask_kxky_radiation**2, mode='same')
+        mask_kxky = np.sqrt(mask_kxky[np.newaxis, :, :])
+        mask_kxky /= np.sum(mask_kxky)
+    elif k_support == 'amplitude':
+        _logger.info(ind_str +'k_support == "amplitude"')
+        mask_kxky = scipy.signal.fftconvolve(mask_kxky_ebeam, mask_kxky_radiation, mode='same')
+        mask_kxky /= np.sum(mask_kxky)
+    elif k_support == 'amplitude':
+        _logger.info(ind_str +'k_support == "beam"')
+        mask_kxky = mask_kxky_ebeam
+    else:
+        raise ValueError('k_support should be either "intensity" or "amplitude"')
+    
+    # dfl.fld *= mask_kxky[np.newaxis, :, :]
+    _logger.info(ind_str +'Multiplying by inverse space mask')
+    dfl.fld *= mask_kxky
+    _logger.info(2*ind_str +'done')
+
+    if showfig:
+        plot_dfl(dfl, domains='s', fig_name = '3-X_radaition_size')
+        plot_dfl(dfl, domains='k', fig_name = '3-X_radiation_divergence')
+    
+    return dfl     
 
 def calc_phase_delay_poly(coeff, w, w0):
     """
@@ -1843,6 +2422,79 @@ def dfl_ap_circ(dfl, r=np.inf, center=(0,0)):
 
     return dfl
 
+def dfl_ap_rect_apscan(dfl):
+    """
+    Scans all possible aperture settings and determine resulting energies.
+    """
+    _logger.info('scanning square aperture')
+
+    # obtain possible cut-off levels (still need to filter away "close neighbors", see below)
+    sx = dfl.scale_x();
+    sy = dfl.scale_y();
+
+    '''
+    Filter against "close neighbors", keeping the larger one
+    This is needed because there rounding errors, such as
+      >>> sx[2]
+      yields -0.00192
+      >>> sx[-3]
+      yields 0.0019200000000000007,
+    that would result in some transverse cuts being asymmetric.
+    Remark: Clean solution would be to implement scale_x function 
+    using (i) integer arithmetic to generate array and
+    (ii) then scaling all values by identical multiplication factor.
+    But this would very likely break some other code.
+    '''
+
+    '''
+    NOTE: need to filter x and y vectors separately, then combine them and apply unique operation.
+    Not filtering combined data set, because if there are close neighbors, one is from x and one from y => legit.
+    '''
+    def drop_close_neighbors(q, releps=1.0e-12, dbg=False):
+        q = np.sort(q)
+        qout = []
+        qlc = q[-1] # always remember last element from input vector transferred to output vector
+        qout.append(qlc)
+        if dbg: print('{:.15f} => keep it'.format(qlc))
+        for k in reversed(range(0, len(q)-1)):
+            if (releps*q[k]<qlc-q[k]): # this also works if 'q[k]' is zero...
+                qlc=q[k]
+                qout.append(qlc)
+                if dbg: print('{:.15f} => keep it'.format(qlc))
+            else:
+                if dbg: print('{:.15f} => drop it'.format(q[k]))
+        #
+        qout.reverse() # get it into ascending order again
+        return(np.array(qout))
+
+    sx_filt = drop_close_neighbors(np.sort(np.abs(sx)))
+    sy_filt = drop_close_neighbors(np.sort(np.abs(sy)))
+    cutoffs = np.hstack((sx_filt[:],sy_filt[:]))
+    cutoffs = np.unique(cutoffs) # np.unique returns data in ascending order
+
+    Etot = dfl.E()
+    energies = []
+    for cc in np.nditer(cutoffs):
+        # determine index range meeting cutoff criterion
+        idx_x  = np.where(np.abs(sx)<=cc)[0]
+        idx_y  = np.where(np.abs(sy)<=cc)[0]
+        idx_x1 = idx_x[0]
+        idx_x2 = idx_x[-1]
+        idx_y1 = idx_y[0]
+        idx_y2 = idx_y[-1]
+        # obtain sub-matrix (note: second index is 'y' direction. See for instance member function Ny() of class RadiationField, implemented in wave.py) ...
+        F = dfl.fld[:, idx_y1:idx_y2, idx_x1:idx_x2]
+
+        # ... and compute energy, using code fragments from functions 'intensity(self)' and 'E(self)' in wave.py (commit ID 1f1b2b3, date Jul 13, 2021)
+        u = F.real**2 + F.imag**2
+        E = np.sum(u)
+        if dfl.Nz()>1:
+            E *= dfl.Lz()/dfl.Nz() / speed_of_light
+        energies.append(E)
+    #
+    return energies,cutoffs
+
+
 def dfl_prop(dfl, z, fine=1, debug=1):
     """
     LEGACY, WILL BE DEPRECATED, SEE METHOD
@@ -2131,23 +2783,32 @@ def dfl_interp(dfl, interpN=(1, 1), interpL=(1, 1), newN=(None, None), newL=(Non
 
     _logger.debug(ind_str + 'new shape = (%i %i %i)' % (len(fld2), fslice2.shape[0], fslice2.shape[1]))
 
-    dfl.fld = np.array(fld2)
-    dfl.dx = Lx2 / dfl.Nx()
-    dfl.dy = Ly2 / dfl.Ny()
+    dfl2 = deepcopy(dfl) #TODO:replace with copy except fld
+    dfl2.fld = np.array(fld2)
+    dfl2.dx = Lx2 / dfl2.Nx()
+    dfl2.dy = Ly2 / dfl2.Ny()
     # dfl2.fileName=dfl.fileName+'i'
     # dfl2.filePath=dfl.filePath+'i'
-    E2 = dfl.E()
+    E2 = dfl2.E()
     _logger.info(ind_str + '%.2f%% energy cut' % ((E1 - E2) / E1 * 100))
     _logger.debug(ind_str + 'energy after interpolation ' + str(E2))
     _logger.debug(ind_str + 'done in %.2f sec' % (time.time() - start_time))
 
     if return_result:
-        return dfl
+        return dfl2
     else:
         return
 
 
 def dfl_shift_z(dfl, s, set_zeros=1, return_result=1):
+    """
+    legacy, see dfl_shift_s
+    """
+    _logger.warn('function dfl_shift_z will be deprecated, rename to dfl_shift_s instead')
+    dfl = dfl_shift_s(dfl=dfl, s=s, set_zeros=set_zeros, return_result=return_result)
+    return dfl
+
+def dfl_shift_s(dfl, s, set_zeros=1, return_result=1):
     """
     shift the radiation within the window in time domain
     dfl - initial RadiationField object
@@ -2567,6 +3228,13 @@ def dfl_chirp_freq(dfl, coeff, E_ph0=None, return_result=False):
         # copydfl, dfl = dfl, copydfl
         return dfl
 
+def dfl_xy_corr(dfl, center=(0,0), norm=0):
+    
+    dfl_corr = RadiationField()
+    dfl_corr.copy_param(dfl, version=2)
+    J = dfl.mut_coh_func_c(center=center, norm=norm)
+    dfl_corr.fld = J[np.newaxis,:,:]             
+    return dfl_corr
 
 def generate_1d_profile(hrms, length=0.1, points_number=1000, wavevector_cutoff=0, psd=None, seed=None):
     """
@@ -2806,14 +3474,21 @@ def wigner_out(out, z=inf, method='mp', pad=1, debug=1, on_axis=1):
     """
     returns WignerDistribution from GenesisOutput at z
     """
-    # assert isinstance(out,GenesisOutput) #hotfix
-    assert len(out.s) > 0
-
-    import numpy as np
-
+    
     _logger.info('calculating Wigner distribution from .out at z = {}'.format(str(z)))
+    
+    # assert isinstance(out,GenesisOutput) #hotfix
+    if not hasattr(out, 's'):
+        _logger.error('out file has no s coordinate')
+        return None
+    elif len(out.s) == 0:
+        _logger.error('out file has s coordinate with zero length')
+        return None
+    else:
+        pass
+    
     start_time = time.time()
-
+    
     if z == 'end':
         z = np.inf
     if z == np.inf:
@@ -2823,8 +3498,10 @@ def wigner_out(out, z=inf, method='mp', pad=1, debug=1, on_axis=1):
     elif z < np.amin(out.z):
         z = np.amin(out.z)
     zi = np.where(out.z >= z)[0][0]
-
-    wig = WignerDistribution()
+    
+    _logger.debug(ind_str + 'zi = {}, z[zi] = {}'.format(str(zi), str(out.z[zi])))
+    
+    wig = WignerDistributionLongitudinal()
 
     if on_axis:
         if hasattr(out, 'p_mid'):  # genesis2
@@ -2875,16 +3552,28 @@ def wigner_dfl(dfl, method='mp', pad=1, **kwargs):
 
     _logger.info('calculating Wigner distribution from dfl (on-axis fillament)')
     start_time = time.time()
-
-    wig = WignerDistribution()
-    wig.field = dfl[:, int(dfl.Ny() / 2), int(dfl.Nx() / 2)]
-    wig.s = dfl.scale_z()
+    domain = kwargs.get('domain', 't')
+    
+    #TODO: change dfl slice according to domain
+    if domain == 't':
+        wig = WignerDistributionLongitudinal()
+        wig.field = dfl[:, int(dfl.Ny() / 2), int(dfl.Nx() / 2)]
+        wig.s = dfl.scale_z()
+    elif domain == 'x':
+        wig = WignerDistributionTransverse()
+        wig.field = dfl[int(dfl.Nz() / 2), int(dfl.Ny() / 2), :]
+        wig.s = dfl.scale_x()
+    elif domain == 'y':
+        wig = WignerDistributionTransverse()
+        wig.field = dfl[int(dfl.Nz() / 2), :, int(dfl.Nx() / 2)]
+        wig.s = dfl.scale_y()
+    
     wig.xlamds = dfl.xlamds
     wig.filePath = dfl.filePath
 
     if pad > 1:
         wig = wigner_pad(wig, pad)
-
+    #wig.domain = domain
     wig.eval(method)  # calculate wigner parameters based on its attributes
 
     _logger.debug(ind_str + 'done in %.2f seconds' % (time.time() - start_time))
@@ -2892,7 +3581,7 @@ def wigner_dfl(dfl, method='mp', pad=1, **kwargs):
     return wig
 
 
-def wigner_stat(out_stat, stage=None, z=inf, method='mp', debug=1, pad=1, **kwargs):
+def wigner_stat(out_stat, stage=None, z=inf, method='mp', debug=1, pad=1, on_axis=1, **kwargs):
     """
     returns averaged WignerDistribution from GenStatOutput at stage at z
     """
@@ -2904,10 +3593,10 @@ def wigner_stat(out_stat, stage=None, z=inf, method='mp', debug=1, pad=1, **kwar
     #     pass
     # else:
     #     raise ValueError('unknown object used as input')
-
+    
     _logger.info('calculating Wigner distribution from out_stat at z = {}'.format(str(z)))
     start_time = time.time()
-
+    
     if z == inf:
         z = np.amax(out_stat.z)
     elif z > np.amax(out_stat.z):
@@ -2915,36 +3604,39 @@ def wigner_stat(out_stat, stage=None, z=inf, method='mp', debug=1, pad=1, **kwar
     elif z < np.amin(out_stat.z):
         z = np.amin(out_stat.z)
     zi = np.where(out_stat.z >= z)[0][0]
-
-    # WW = np.zeros((out_stat.p_int.shape[2], out_stat.p_int.shape[1], out_stat.p_int.shape[1]))
-
+    
+    if on_axis:
+        power = out_stat.p_mid
+    else:
+        power = out_stat.p_int
+    
+    # WW = np.zeros((power.shape[2], power.shape[1], power.shape[1]))
     if pad > 1:
         n_add = out_stat.s.size * (pad - 1) / 2
         n_add_l = int(n_add - n_add % 2)
         n_add_r = int(n_add + n_add % 2)
+        n_add = n_add_l + n_add_r
         ds = (out_stat.s[-1] - out_stat.s[0]) / (out_stat.s.size - 1)
         pad_array_s_l = np.linspace(out_stat.s[0] - ds * (n_add_l), out_stat.s[0] - ds, n_add_l)
         pad_array_s_r = np.linspace(out_stat.s[-1] + ds, out_stat.s[-1] + ds * (n_add_r), n_add_r)
+        
         WW = np.zeros(
-            (out_stat.p_int.shape[2], out_stat.p_int.shape[1] + n_add * 2, out_stat.p_int.shape[1] + n_add * 2))
+            (power.shape[2], power.shape[1] + n_add, power.shape[1] + n_add))
         s = np.concatenate([pad_array_s_l, out_stat.s, pad_array_s_r])
     else:
-        WW = np.zeros((out_stat.p_int.shape[2], out_stat.p_int.shape[1], out_stat.p_int.shape[1]))
+        WW = np.zeros((power.shape[2], power.shape[1], power.shape[1]))
         s = out_stat.s
-
     # _logger.debug('n_add {}'.format(n_add))
     # _logger.debug('n_add_l {}'.format(n_add_l))
     # _logger.debug('n_add_r {}'.format(n_add_r))
     # _logger.debug('field {}'.format(field.shape))
     # _logger.debug('wig {}'.format(WW.shape))
-
     for (i, n) in enumerate(out_stat.run):
         _logger.debug(ind_str + 'run {} of {}'.format(i, len(out_stat.run)))
-        field = np.sqrt(out_stat.p_int[zi, :, i]) * np.exp(1j * out_stat.phi_mid[zi, :, i])
+        field = np.sqrt(power[zi, :, i]) * np.exp(1j * out_stat.phi_mid[zi, :, i])
         if pad > 1:
             field = np.concatenate([np.zeros(n_add_l), field, np.zeros(n_add_r)])
         WW[i, :, :] = calc_wigner(field, method=method, debug=debug, **kwargs)
-
     wig = WignerDistribution()
     wig.wig = np.mean(WW, axis=0)
     wig.wig_stat = WW
@@ -2957,9 +3649,7 @@ def wigner_stat(out_stat, stage=None, z=inf, method='mp', debug=1, pad=1, **kwar
     ds = wig.s[1] - wig.s[0]
     phen = h_eV_s * (np.fft.fftfreq(wig.s.size, d=ds / speed_of_light) + speed_of_light / wig.xlamds)
     wig.phen = np.fft.fftshift(phen, axes=0)
-
     _logger.debug(ind_str + 'done in %.2f seconds' % (time.time() - start_time))
-
     return wig
 
 
@@ -2971,6 +3661,7 @@ def wigner_smear(wig, sigma_s):
     :param sigma_s: [meters] rms size of the s=-ct the gaussian window func
     :return: convolved ocelot.optics.wave.WignerDistribution object with gaussian window function
     """
+    #TODO: extend to transverse direction, move to class?
     start = time.time()
     _logger.info('smearing wigner_dist with gaussian window func')
     xlamds = wig.xlamds
@@ -2989,6 +3680,97 @@ def wigner_smear(wig, sigma_s):
     _logger.debug(ind_str + 'done in {:.2e} sec'.format(time.time() - start))
     return wig_conv
 
+def write_wig_file(wig, filePath):
+    _logger.info('saving wigner distribution to {}'.format(filePath))
+    np.savez(filePath, xlamds=wig.xlamds, s=wig.s, k=wig.k, wig=wig.wig, wig_stat=wig.wig_stat, domain=wig.domain, filePath = wig.filePath)
+    _logger.debug(ind_str + 'done')
+    
+def read_wig_file_legacy(filePath):
+    _logger.info('reading wigner distribution from {}'.format(filePath))
+    file = np.load(filePath)
+    wig = WignerDistribution()
+    wig.xlamds = file['xlamds'].item()
+    wig.filePath = file['filePath'].item()
+    wig.s = file['s']
+    wig.phen = file['phen']
+    wig.wig = file['wig']
+    _logger.debug(ind_str +'wig.wig.shape {}'.format(wig.wig.shape))
+    wig.wig_stat = file['wig_stat']
+    _logger.debug(ind_str +'wig.wig_stat.shape {}'.format(wig.wig_stat.shape))
+    _logger.debug(ind_str + 'done')
+    return wig
+
+def read_wig_file_legacy(filePath):
+    _logger.info('reading wigner distribution from {}'.format(filePath))
+    file = np.load(filePath)
+    wig = WignerDistribution()
+    wig.xlamds = file['xlamds'].item()
+    wig.filePath = file['filePath'].item()
+    wig.s = file['s']
+    wig.k = file['k']
+    wig.domain = file['doimain']
+    wig.wig = file['wig']
+    _logger.debug(ind_str +'wig.wig.shape {}'.format(wig.wig.shape))
+    wig.wig_stat = file['wig_stat']
+    _logger.debug(ind_str +'wig.wig_stat.shape {}'.format(wig.wig_stat.shape))
+    _logger.debug(ind_str + 'done')
+    return wig
+
+
+def write_field_file(dfl, filePath, version=1.0):
+    """
+    Parameters
+    ----------
+    dfl : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+    filePath : str
+        file path where to write the dfl file
+    version : float, optional
+        DESCRIPTION. The default is 1
+    Returns
+    -------
+    None.
+
+    """
+    _logger.info('saving RadiationField object')
+    _logger.debug(ind_str + 'saving to ' + filePath)
+    np.savez(filePath, dx=dfl.dx, dy=dfl.dy, dz=dfl.dz, Nz=dfl.Nz(), Ny=dfl.Ny(), Nx=dfl.Nx(), 
+          xlamds=dfl.xlamds, domain_z=dfl.domain_z, domain_xy=dfl.domain_xy, filePath=filePath, fld=dfl.fld, version=version) # maybe automatically iterate through attributes so we don't miss anything. if so, version should be defined by ocelot version -> RadiationField version -> dfl.npz
+    
+    _logger.info(ind_str + 'done')
+
+def read_field_file(filePath):
+    """
+    Parameters
+    ----------
+    filePath : str
+        file path where to write the dfl file.
+
+    Returns
+    -------
+    dfl : RadiationField object
+        3d or 2d coherent radiation distribution, *.fld variable is the same as Genesis dfl structure
+
+    """
+    _logger.info('reading RadiationField object from {}'.format(filePath))
+   
+    file = np.load(filePath + '.npz', allow_pickle=True)
+    
+    ### the .npz file attributes
+    dfl = RadiationField((file['Nz'].item(), file['Ny'].item(), file['Nx'].item()))
+    dfl.dz, dfl.dy, dfl.dx = file['dz'].item(), file['dy'].item(), file['dx'].item()
+    dfl.domain_xy = file['domain_xy'].item()
+    dfl.domain = file['domain_z'].item()
+    dfl.xlamds = file['xlamds'].item()
+    dfl.fld = file['fld']
+    dfl.filePath = file['filePath'].item()    
+
+    _logger.debug(ind_str + 'loaded file version is {} ...'.format(file['version'].item()))
+      ###
+    
+    _logger.debug(ind_str +'dfl.fld.shape {}'.format(dfl.fld.shape))
+    _logger.info(ind_str + 'done')
+    return dfl
 
 def calc_ph_sp_dens(spec, freq_ev, n_photons, spec_squared=1):
     """
@@ -3035,6 +3817,7 @@ def calc_ph_sp_dens(spec, freq_ev, n_photons, spec_squared=1):
     return spec
 
 
+
 def imitate_1d_sase_like(td_scale, td_env, fd_scale, fd_env, td_phase=None, fd_phase=None, phen0=None, en_pulse=None,
                          fit_scale='td', n_events=1, **kwargs):
     """
@@ -3236,4 +4019,4 @@ def dfldomain_check(domains, both_req=False):
         order does not matter
         
         **kwargs are passed down to self.fft_z and self.fft_xy
-        """
\ No newline at end of file
+        """
diff --git a/ocelot/rad/fel.py b/ocelot/rad/fel.py
index 3de4c4a8..2686e455 100644
--- a/ocelot/rad/fel.py
+++ b/ocelot/rad/fel.py
@@ -34,6 +34,8 @@ def eval(self, method='mxie'):
         
         if not hasattr(self, 'hn'):
             self.hn=1 #harmonic number
+        if (self.hn<1) or (self.hn%1):
+            _logger.warning('parameter hn must be positive integer')
         
         if np.any(self.betax <= 0) or np.any(self.betay <= 0):
             _logger.warning('betax or betay <= 0, returning lg3=np.nan')
@@ -83,11 +85,11 @@ def eval(self, method='mxie'):
         
         # self.N = self.I * self.lambda0 / 1.4399644850445153e-10
         # self.sigb = 0.5 * (self.rxbeam + self.rybeam) # average beam size
+                # h_eV_s * speed_of_light / self.lambda0
         
+        ### Check criterion given in Eq.6, 10.1103/PhysRevSTAB.15.080702
         emit_n = np.sqrt(self.emitx * self.emity)
-        # h_eV_s * speed_of_light / self.lambda0
         self.emit_nn = 2 * np.pi * emit_n / self.lambdah / self.gamma0 ## emittance normalized as in Eq.6, 10.1103/PhysRevSTAB.15.080702
-        
         if (np.any(self.emit_nn < 1) or np.any(self.emit_nn) > 5):
             self.inaccurate = True 
             if tdp:
@@ -106,7 +108,8 @@ def eval(self, method='mxie'):
         
         if method == 'mxie':
             '''
-            M. Xie, “Exact and variational solutions of 3D eigenmodes in high gain FELs,” Nucl. Instruments Methods Phys. Res. Sect. A Accel. Spectrometers, Detect. Assoc. Equip., vol. 445, no. 1–3, pp. 59–66, 2000.
+            M. Xie, "Exact and variational solutions of 3D eigenmodes in high gain FELs", Nucl. Instruments Methods Phys. Res. Sect. A Accel. Spectrometers, Detect. Assoc. Equip., vol. 445, no. 1--3, pp. 59--66, 2000.
+            DOI https://doi.org/10.1016/S0168-9002(00)00114-5
             '''
             
             # if self.hn != 1:
@@ -149,7 +152,8 @@ def eval(self, method='mxie'):
             #eq.4, DOI:10.1103/PhysRevSTAB.15.080702
             # it is power gain length = 0.5 * field gain length
             
-            self.delta = 131 * (I_Alfven / self.I) * emit_n**(5/4) / (self.lambdah * self.xlamd**9)**(1/8) * self.hn**(9/8) * self.delgam**2 / (self.aw0 * self.fch)**2 / (1 + self.aw0**2)**(1/8) #eq.5, DOI:10.1103/PhysRevSTAB.15.080702
+            self.delta = 131 * (I_Alfven / self.I) * emit_n**(5/4) / (self.lambdah * self.xlamd**9)**(1/8) * self.hn**(9/8) * self.delgam**2 / (self.aw0 * self.fch)**2 / (1 + self.aw0**2)**(1/8) 
+            #eq.5, DOI:10.1103/PhysRevSTAB.15.080702
             
                 
             
@@ -389,7 +393,13 @@ def idx(self):
             idx = None
         return idx
     
-    
+# def calculate_fel_parameters_g4(input, array=False, method='mxie'):
+#     p = FelParameters()
+#     p.gamma0 = input.sequence['setup'].gamma0
+#     p.delgam = "n/a" # TODO: think, how to consistently get beam and undulator parameters and update meshes: e.g.
+#     # transverse mesh can be provided externally with field
+#     return
+
 
 def calculateFelParameters(input, array=False, method='mxie'):
     
diff --git a/ocelot/rad/fel_estimator.py b/ocelot/rad/fel_estimator.py
index c157a93e..e692c68f 100644
--- a/ocelot/rad/fel_estimator.py
+++ b/ocelot/rad/fel_estimator.py
@@ -13,7 +13,7 @@
 
 _logger = logging.getLogger(__name__)
 
-def beamlat2fel(beam, lat, smear_m=None, method='mxie', qf=0):
+def beamlat2fel(beam, lat, smear_m=None, method='mxie', qf=0, **kwargs):
     
     _logger.info('estimating fel from beam and lat')
     
@@ -35,14 +35,14 @@ def beamlat2fel(beam, lat, smear_m=None, method='mxie', qf=0):
         raise ValueError('unknown undulator: neither planar nor helical, estimation not applicable')
     
     if smear_m is None:
-        tcoh = beam2fel(beam_pk, l_period, K_peak, iwityp=iwityp).tcoh()
+        tcoh = beam2fel(beam_pk, l_period, K_peak, iwityp=iwityp, **kwargs).tcoh()
         smear_m = tcoh * speed_of_light * 4 #smear window
 
     beam_tmp = deepcopy(beam)
     beam_tmp.smear(smear_m)
     update_effective_beta(beam_tmp, lat)
     beam_tmp.I[beam_tmp.I==0] = np.nan
-    fel = beam2fel(beam_tmp, l_period, K_peak, method='mxie', qf=qf)
+    fel = beam2fel(beam_tmp, l_period, K_peak, method='mxie', qf=qf, **kwargs)
     
     return fel
 
diff --git a/ocelot/rad/optics_elements.py b/ocelot/rad/optics_elements.py
index e7b045f8..1fd84a3a 100644
--- a/ocelot/rad/optics_elements.py
+++ b/ocelot/rad/optics_elements.py
@@ -1,74 +1,74 @@
-"""
-
-"""
 import numpy as np
 
+from ocelot.common.ocelog import *
+_logger = logging.getLogger(__name__)
 
-class OpticsElement:
-    def __init__(self, eid=None):
-        self.eid = eid
-        self.domain = "sf"
-
-    def apply(self, dfl):
-        pass
 
-
-class OpticsMarker(OpticsElement):
+class OpticsElement:
     """
-    Drift element
+    Parent class Optics element
+    :param eid: element id, (for example 'KB')  
     """
     def __init__(self, eid=None):
-        OpticsElement.__init__(self, eid=eid)
-
-    def apply(self, dfl):
-        pass
-
-
-
+        self.eid = eid
+        
+#    def apply(self, dfl): #is this method need?
+#        """
+#        TODO
+#        write documentation
+#        """
+#        get_transfer_function(self)
+#        self.mask.apply(self.mask, dfl)
+           
 class FreeSpace(OpticsElement):
     """
-    Drift element
+    Class for Drift element 
+    :param OpticsElement(): optics element parent class with following parameters
+        :param eid: element id, (for example 'KB')  
+    :param l: propagation distance, [m]
+    :param mx: is the output x mesh size in terms of input mesh size (mx = Lx_out/Lx_inp)
+    :param my: is the output y mesh size in terms of input mesh size (my = Ly_out/Ly_inp)
     """
-    def __init__(self, l=0., mx=1, my=1, eid=None):
+    def __init__(self, l=0., mx=1, my=1, method='PropMask', eid=None):
         OpticsElement.__init__(self, eid=eid)
         self.l = l
         self.mx = mx
         self.my = my
-
+        self.method = method  #method of propagation, also may be 
+                                # 'Fraunhofer_Propagator'
+                                # 'Fresnel_Propagator' . . .
 
 class ThinLens(OpticsElement):
     """
-    Lens element
+    Class for Lens element
+    :param OpticsElement(): optics element parent class with following parameters
+        :param eid: element id, (for example 'KB') 
+    :param fx: focus length in x direction, [m]
+    :param fy: focus length in y direction, [m]
     """
-
     def __init__(self, fx=np.inf, fy=np.inf, eid=None):
         OpticsElement.__init__(self, eid=eid)
         self.fx = fx
         self.fy = fy
-
-
-class Mirror(OpticsElement):
-    def __init__(self, lx=np.inf, ly=np.inf, angle=0., height_error_profile=None, eid=None):
-        OpticsElement.__init__(self)
-        self.lx = lx
-        self.ly = ly
-        self.angle = angle
-        self.height_error_profile = height_error_profile
-
-
+        
 class Aperture(OpticsElement):
     """
     Aperture
+    :param eid: id of the optical element
     """
-
     def __init__(self, eid=None):
         OpticsElement.__init__(self, eid=eid)
-
-
+        
 class ApertureRect(Aperture):
     """
-    Aperture
-
+    Rectangular aperture
+    :param Aperture(): optics element parent class with following parameters
+        :param eid: element id, (for example 'KB', 'Aperture') 
+    :param lx: horizonatal size of the aperture, [m]
+    :param ly: vertical size of the aperture, [m]
+    :param cx: x coprdinate coordinate of the aperture center, [m] 
+    :param cy: y coprdinate coordinate of the aperture center, [m] 
+    :param eid: id of the optical element
     """
 
     def __init__(self, lx=np.inf, ly=np.inf, cx=0., cy=0., eid=None):
@@ -78,10 +78,14 @@ def __init__(self, lx=np.inf, ly=np.inf, cx=0., cy=0., eid=None):
         self.cx = cx
         self.cy = cy
 
-
 class ApertureEllips(Aperture):
     """
-    Aperture
+    Elliptical Aperture
+    :param ax: ellipse x main axis, [m]
+    :param ay: ellipse y main axis, [m]
+    :param cx: ellipse x coordinate of center, [m] 
+    :param cy: ellipse y coordinate of center, [m] 
+    :param eid: id of the optical element
     """
 
     def __init__(self, ax=np.inf, ay=np.inf, cx=0., cy=0., eid=None):
@@ -90,20 +94,35 @@ def __init__(self, ax=np.inf, ay=np.inf, cx=0., cy=0., eid=None):
         self.ay = ay
         self.cx = cx
         self.cy = cy
-
-
-class HeightErrorProfile():
+             
+      
+class DispersiveSection(OpticsElement):
     """
-    Drift element
+    Dispersive Section
+        :param coeff:  
+            coeff[0] =: measured in [rad]      --- phase
+            coeff[1] =: measured in [fm s ^ 1] --- group delay
+            coeff[2] =: measured in [fm s ^ 2] --- group delay dispersion (GDD)
+            coeff[3] =: measured in [fm s ^ 3] --- third-order dispersion (TOD)
+            ...
+        :param E_ph0: energy with respect to which the phase shift is calculated
+    """  
+    def __init__(self, coeff=[0], E_ph0=None, eid=None):
+        OpticsElement.__init__(self, eid=None)
+        self.coeff = coeff
+        self.E_ph0 = E_ph0
+
+
+class ImperfectMirrorSurface(OpticsElement):
     """
-    def __init__(self, hrms=0, lx=1., ly=1., nx=1000, ny=1000, k_cutoff=0., psd=None, eid=None):
-        self.eid = eid
+    TODO
+    write documentation
+    """
+    def __init__(self, height_profile=None, hrms=0, lx=np.inf, ly=np.inf, angle=np.pi * 2 / 180, plane='x', eid=None):
+        OpticsElement.__init__(self, eid=eid)
+        self.height_profile = height_profile
         self.hrms = hrms
         self.lx = lx
         self.ly = ly
-        self.nx = nx
-        self.ny = ny
-        self.k_cutoff = k_cutoff
-        self.psd = psd
-
-
+        self.angle=angle
+        self.plane=plane
diff --git a/ocelot/rad/optics_line.py b/ocelot/rad/optics_line.py
index 658d08e7..d3063e99 100644
--- a/ocelot/rad/optics_line.py
+++ b/ocelot/rad/optics_line.py
@@ -1,26 +1,54 @@
-from ocelot.rad.optics_elements import *
+from copy import deepcopy
+import numpy as np
+
+from ocelot.common.globals import *
 from ocelot.rad.transfer_function import *
+from ocelot.rad.optics_elements import *
+
 from ocelot.common.ocelog import *
-import copy
 _logger = logging.getLogger(__name__)
-ocelog.setLevel(logging.DEBUG)
 
 flatten = lambda *n: (e for a in n
                       for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))
 
-
 class OpticsLine():
     def __init__(self, sequence, start=None, stop=None):
         self.sequence = list(flatten(sequence))
         self.stop = stop
         self.start = start
+        
+        _logger.info(ind_str + 'beamline sequence {}'.format(self.sequence))
+        
+        self.sequence = self.get_sequence_part(start, stop)
+        
         self.update_optics_masks()
-
+        
+    def get_sequence_part(self, start, stop):
+        try:
+            if start is not None:
+                id1 = self.sequence.index(start)
+            else:
+                id1 = 0 
+
+            _logger.info(ind_str + 'sequence the first element {} and its index {}'.format(self.start, id1))
+
+            if stop is not None:
+                id2 = self.sequence.index(stop) + 1
+                sequence = self.sequence[id1:id2]
+                _logger.info(ind_str + 'sequence the last element {} and its index {}'.format(self.start, id2))
+            else: 
+                sequence = self.sequence[id1:]
+                
+            _logger.info(ind_str + 'beamline sequence {}'.format(self.sequence))
+            
+        except:
+            _logger.error(ind_str + 'cannot construct sequence, element not found')
+            raise
+            
+        return sequence
+        
     def update_optics_masks(self):
-        print("update mask")
-
         for element in self.sequence:
-            print(element)
 
             get_transfer_function(element)
 
@@ -28,11 +56,49 @@ def estimate_mesh(self):
         for element in self.sequence:
             element.mesh = 0
 
-
-
-
-
-
-
-
-
+def get_transfer_function(element):
+    """
+    Matchs OpticalElement object to its mask. Several masks can correspond to one OpticalElement object 
+    The function rewrites OpticalElement object parameters to Mask object parameters
+    
+    :param element: OpticsElement class
+    """
+    element.mask = Mask()
+
+    if element.__class__ is None:
+        raise ValueError('Optics element must belong to the OpticsElement class')
+
+    elif element.__class__ is FreeSpace: #implementation of several masks
+        if element.method in ['PropMask', 'PropMask_kf', 'PropMask_kt']:
+            if element.mx == 1 and element.my == 1:
+                element.mask = PropMask(element.l, element.method)                
+            elif element.mx != 1 and element.my != 1:
+                element.mask = Prop_mMask(element.l, element.mx, element.my, element.method)
+            else:
+                ValueError("mx and my must be positive non-zero values")
+        elif element.type == 'Fraunhofer_Propagator':
+            _logger.warn('Fraunhofer Propagation method has not implemented yet')
+            pass    
+        elif element.type == 'Fresnel_Propagator':
+            _logger.warn('Fresnel Propagation method has not implemented yet')          
+            pass                               
+        else:            
+            raise ValueError('Propagator method can be PropMask (see Tutorials), Fraunhofer_Propagator or Fresnel_Propagator')    
+        
+    elif element.__class__ is ThinLens: 
+        element.mask = LensMask(element.fx, element.fy)
+  
+    elif element.__class__ is ApertureRect: 
+        element.mask = ApertureRectMask(element.lx, element.ly, element.cx, element.cy)
+        
+    elif element.__class__ is ApertureEllips: #no checked
+        element.mask = ApertureEllipsMask(element.ax, element.ay, element.cx, element.cy)
+        
+    elif element.__class__ is DispersiveSection: #no checked
+        element.mask = PhaseDelayMask(element.coeff, element.E_ph0)
+        
+    elif element.__class__ is ImperfectMirrorSurface: #no checked
+        element.mask = MirrorMask(element.height_profile, element.hrms, element.angle, element.plane, element.lx, element.ly)
+
+    else:
+        raise ValueError('Optics element must belong to one of the child OpticsElement classes')
diff --git a/ocelot/rad/propagation.py b/ocelot/rad/propagation.py
index 9c1a0b0f..eee7c149 100644
--- a/ocelot/rad/propagation.py
+++ b/ocelot/rad/propagation.py
@@ -1,17 +1,16 @@
-
-def propagate(optics_line, dfl, optimize=True, dump=False):
-    if optimize:
+def propagate(optics_line, dfl, optimize=False, dump=False):
+    
+    if optimize: #not implemented
         estimate_masks(optics_line, dfl)
         combine_elements(optics_line)
-
+            
     for element in optics_line.sequence:
-
         element.mask.apply(dfl)
     return dfl
 
-def estimate_masks(optics_line, dfl):
+def estimate_masks(optics_line, dfl):#not implemented
     for element in optics_line.sequence:
         element.mask.get_mask(dfl)
 
-def combine_elements(optics_line):
+def combine_elements(optics_line):#not implemented
     return optics_line
\ No newline at end of file
diff --git a/ocelot/rad/transfer_function.py b/ocelot/rad/transfer_function.py
index abf214b8..c841df4a 100644
--- a/ocelot/rad/transfer_function.py
+++ b/ocelot/rad/transfer_function.py
@@ -1,125 +1,795 @@
-from ocelot.optics.wave import *
-from ocelot.rad.optics_elements import *
-from ocelot.rad.optics_line import *
-from ocelot.common.ocelog import *
+import logging
+import time
+
 import numpy as np
-import copy
-_logger = logging.getLogger(__name__)
+from copy import deepcopy
+from math import factorial
+
+from ocelot.optics.new_wave import *
+from ocelot.common.globals import *
+from ocelot import ocelog
+from ocelot.common.ocelog import *
+_logger = logging.getLogger(__name__) 
 
+class Mask(Grid):
+    """
+    Mask element class
+    The class represents a transfer function of an optical element. Note, several masks can correspond to one optical element.
+    :param Grid: with following parameters  
+        :params (dx, dy, dz): spatial step of the mesh, [m] 
+        :param shape: number of point in each direction of 3D data mesh
+        :param xlamds: carrier wavelength of the wavepacket, [m]
+        :param used_aprox: the approximation used in solving the wave equation. OCELOT works in Slowly Varying Amplitude Approximation
+    :param domain_z: longitudinal domain (t - time, f - frequency)   
+    :param domain_x: transverse domain (s - space, k - inverse space)      
+    :param domain_y: transverse domain (s - space, k - inverse space)       
+    """
+    def __init__(self, shape=(0, 0, 0)):
+        Grid.__init__(self, shape=shape)
+        self.msk = None#np.zeros(shape, dtype=complex128)  # (z,y,x)
+        # self.domain_z = 't'   # longitudinal domain (t - time, f - frequency)
+        # self.domain_x = 's'   # transverse domain (s - space, k - inverse space)
+        # self.domain_y = 's'   # transverse domain (s - space, k - inverse space)
+        
+    def __mul__(self, other):#check this stuff when it will been needed
+        """
+        Multiplication operator for two masks 
+        """
+        m = deepcopy(self)
+        if other.__class__ in [self] and self.mask is not None and other.mask is not None:
+            m.mask = self.mask * other.mask
+            return m
+        else: ValueError("'other' must belong to Mask class") 
+    
+    # def _shape(self):
+    #     '''
+    #     returns the shape of fld attribute
+    #     '''
+    #     return self.mask.shape
+    
+class PropMask(Mask):
+    """
+    Angular-spectrum propagation for fieldfile
+    
+    can handle wide spectrum
+      (every slice in freq.domain is propagated
+       according to its frequency)
+    no kx**2+ky**2<<k0**2 limitation
+    
+    dfl is the RadiationField() object
+    
+    z0 is the propagation distance in [m]
+    for 'kt' domain propagation
+        no Fourier transform to frequency domain is done
+        assumes no angular dispersion (true for plain FEL radiation)
+        assumes narrow spectrum at center of xlamds (true for plain FEL radiation)
+    'kf' propagation is a default option
+    
+    z>0 -> forward direction
+    z<0 -> backward direction
+    z=0 return original
+    """   
+    def __init__(self, z0, method='PropMask_kf'):
+        Mask.__init__(self)
+        self.z0 = z0 
+        self.method = method
+        # self.mask = None
 
-def get_transfer_function(element):
-    element.mask = Mask()
+    def apply(self, dfl):
+        """
+        'apply' method for PropMask class 
+        
+        transform dfl to the domain of the propagation 'kf' or 'kt'
+        get the transfer function calling 'get_mask' method, e.g. get H transfer function 
+        multiply dfl and the mask, e.g. E = E_0 * H convolution in inverse space domain
+        return the field to the original domain
+        """
+        
+        _logger.info('propagating dfl file by %.2f meters' % (self.z0))
+        
+        if self.z0 == 0:
+            _logger.debug(ind_str + 'z0=0, returning original')
+            return dfl
 
-    if element.__class__ is ApertureRect:
-        mask = RectMask()
-        mask.lx = element.lx
-        mask.ly = element.ly
-        element.mask = mask
-    elif element.__class__ is FreeSpace:
-        element.mask = DriftMask(element.l, element.mx, element.my)
-    elif element.__class__ is ThinLens:
-        element.mask = LensMask(element.fx, element.fy)
+        start = time.time()
 
+        domains = dfl.domains()
+        self.domain_x = 'k'
+        self.domain_y = 'k'
+        if self.method in ['PropMask', 'PropMask_kf']:
+            dfl.to_domain('kf')
+            self.domain_x = 'f'
+        elif self.method == 'PropMask_kt':
+            dfl.to_domain('kt')
+            self.domain_x = 't'
+        else:
+            raise ValueError("propagation method should be 'PropMask', 'PropMask_kf' or 'PropMask_kt'")
+                         
+        if self.msk is None:
+            self.get_mask(dfl) # get H transfer function 
 
-class Mask:
-    def __init__(self):
-        pass
+        dfl.fld *= self.msk # E = E_0 * H convolution in inverse space domain
+        
+        dfl.to_domain(domains) # back to original domain  
 
-    def apply(self, dfl):
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in %.2f sec' % t_func)
+        
         return dfl
+        
+    def get_mask(self, dfl):
+        """
+        'get_mask' method for PropMask class
+        find the transfer function for propagation in 'kf' of 'ks' domains
+        H = exp(iz0(k^2 - kx^2 - ky^2)^(1/2) - k) 
+        """
+        self.copy_grid(dfl)
+       
+        k_x, k_y = np.meshgrid(dfl.grid_kx(), dfl.grid_ky())
+        
+        _logger.debug(ind_str + 'calculating mask in "{}" domain'.format(dfl.domain_z))                 
+        
+        if dfl.domain_z == 'f':
+            k = dfl.grid_kz()
+            self.msk = np.ones(dfl.shape(), dtype=complex128)
+            # self.msk = [np.exp(1j * self.z0 * (np.sqrt(k[i] ** 2 - k_x ** 2 - k_y ** 2) - k[i])) for i in range(dfl.Nz())] 
+            for i in range(dfl.Nz()):
+                self.msk[i,:,:] *= np.exp(1j * self.z0 * (np.sqrt(k[i] ** 2 - k_x ** 2 - k_y ** 2) - k[i]))
+
+        elif dfl.domain_z == 't':
+            k = 2 * np.pi / self.xlamds
+            self.msk = np.ones(dfl.shape()[1:3], dtype=complex128)
+            self.msk = np.exp(1j * self.z0 * (np.sqrt(k ** 2 - k_x ** 2 - k_y ** 2) - k))
+        
+        else: 
+            raise ValueError('wrong field domain, domain must be ks or kf ')    
+ 
+        _logger.debug(ind_str + 'transfer function mask shape {}'.format(self.msk.shape))         
+        return self.msk
+
+class Prop_mMask(Mask):
+    """
+    Angular-spectrum propagation for fieldfile
+    
+    can handle wide spectrum
+      (every slice in freq.domain is propagated
+       according to its frequency)
+    no kx**2+ky**2<<k0**2 limitation
+    
+    dfl is the RadiationField() object
+    
+    z0 is the propagation distance in [m]
+    m is the output mesh size in terms of input mesh size (m = L_out/L_inp)
+    for 'ks' domain propagation
+        no Fourier transform to frequency domain is done
+        assumes no angular dispersion (true for plain FEL radiation)
+        assumes narrow spectrum at center of xlamds (true for plain FEL radiation)
+    'kf' propagation is a default option
+    
+    z>0 -> forward direction
+    z<0 -> backward direction
+    z=0 return original
+    """   
+    
+    def __init__(self, z0, mx, my, method):
+        Mask.__init__(self)
+        self.z0 = z0
+        self.mx = mx
+        self.my = my
+        self.method = method
 
     def get_mask(self, dfl):
-        pass
+        """
+        'get_mask' method for Prop_mMask class
+        find the transfer function for propagation in 'kf' of 'ks' domains
+        H = exp(iz0(k^2 - kx^2 - ky^2)^(1/2) - k) 
+        """
+        self.copy_grid(dfl)
+        
+        k_x, k_y = np.meshgrid(dfl.grid_kx(), dfl.grid_ky())
 
-    def __mul__(self, other):
-        m = copy.deepcopy(self)
-        if other.__class__ in [self] and self.mask is not None and other.mask is not None:
-            m.mask = self.mask * other.mask
-            return m
+        _logger.debug(ind_str + 'calculating mask in "{}" domain'.format(dfl.domain_z))                 
+        if dfl.domain_z == 'f':
+            # self.msk = np.array([])#np.zeros(dfl.shape(), dtype=complex128)#np.ones(dfl.shape(), dtype=complex128)
+            self.msk = np.ones(dfl.shape(), dtype=complex128)
+            k = dfl.grid_kz()
+            if self.mx != 0:
+#                self.mask[i,:,:] *= [np.exp(1j * self.z0/self.mx * (np.sqrt(k[i] ** 2 - k_x ** 2) - k[i])) for i in range(dfl.Nz())] #Hx = exp(iz0/mx(k^2 - kx^2)^(1/2) - k)
+                for i in range(dfl.Nz()):
+                    self.msk[i,:,:] *= np.exp(1j * self.z0 / self.mx * (np.sqrt(k[i] ** 2 - k_x ** 2) - k[i]))
+            if self.my != 0:
+#                self.mask[i,:,:] *= [np.exp(1j * self.z0/self.my * (np.sqrt(k[i] ** 2 - k_y ** 2) - k[i])) for i in range(dfl.Nz())] #Hy = exp(iz0/my(k^2 - ky^2)^(1/2) - k)                   
+                for i in range(dfl.Nz()):
+                    self.msk[i,:,:] *= np.exp(1j * self.z0 / self.my * (np.sqrt(k[i] ** 2 - k_y ** 2) - k[i]))
+        
+        elif dfl.domain_z == 't':
+            self.msk = np.ones(dfl.shape()[1:3], dtype=complex128)
+            k = 2 * np.pi / self.xlamds
+            
+            if self.mx != 0:
+                self.msk*= np.exp(1j * self.z0/self.mx * (np.sqrt(k ** 2 - k_x ** 2) - k))# for i in range(dfl.Nz())] 
+            if self.my != 0:
+                self.msk*= np.exp(1j * self.z0/self.my * (np.sqrt(k ** 2 - k_y ** 2) - k))# for i in range(dfl.Nz())]          
+        else: 
+            raise ValueError("wrong field domain, domain must be 'ks' or 'kf'")    
+
+        _logger.debug(ind_str + 'transfer function mask shape {}'.format(self.msk.shape))         
+        return self.msk    
+    
+    def apply(self, dfl):
+        
+        """
+        'apply' method for Prop_mMask class 
+        
+        transform dfl to the domain of the propagation 'kf' or 'kt'
+        transforming the wavefront curvature transform by a phase factor z0/(1 - m)
+        get the transfer function calling 'get_mask' method, e.g. get H transfer function 
+        multiply dfl and the mask, e.g. E = E_0 * H convolution in inverse space domain
+        transverce mesh step resizing 
+        return the field to the original domain
+        transforming the wavefront curvature transform by a phase factor -m*z0/(m - 1) --- inverse transformation
+        """   
+        _logger.info('propagating dfl file by %.2f meters' % (self.z0))
 
+        if self.z0 == 0:
+            _logger.debug(ind_str + 'z0=0, returning original')
+            return dfl
+        
+        start = time.time()
+    
+        if self.mx != 1:
+#            dfl.curve_wavefront(-self.z0 / (1 - self.mx), plane='x')
+            dfl = QuadCurvMask(r = -self.z0 / (1 - self.mx), plane='x').apply(dfl)
+        if self.my != 1:
+#            dfl.curve_wavefront(-self.z0 / (1 - self.my), plane='y')
+            dfl = QuadCurvMask(r = -self.z0 / (1 - self.my), plane='y').apply(dfl)
 
-class RectMask(Mask):
-    def __init__(self):
+        domains = dfl.domains()      
+        self.domain_x = 'k'
+        self.domain_y = 'k'
+        if self.method in ['PropMask', 'PropMask_kf']:
+            dfl.to_domain('kf')
+            self.domain_x = 'f'
+        elif self.method == 'PropMask_kt':
+            dfl.to_domain('kt')
+            self.domain_x = 't'
+        else:
+            raise ValueError("propagation method should be 'PropMask', 'PropMask_kf' or 'PropMask_kt'")
+        
+        if self.msk is None:
+            self.msk = self.get_mask(dfl) # get H transfer function 
+            
+        dfl.fld *= self.msk #E = E_0 * H convolution in inverse space domain
+               
+        dfl.dx *= self.mx #transform grid to output mesh size
+        dfl.dy *= self.my        
+        self.dx *= self.mx #transform grid to output mesh size
+        self.dy *= self.my   
+        
+        dfl.to_domain(domains) # back to the original domain
+        
+        if self.mx != 1:
+#            dfl.curve_wavefront(-self.mx * self.z0 / (self.mx - 1), plane='x')
+            dfl = QuadCurvMask(r = -self.mx * self.z0 / (self.mx - 1), plane='x').apply(dfl)
+        if self.my != 1:
+#            dfl.curve_wavefront(-self.my * self.z0 / (self.my - 1), plane='y')
+            dfl = QuadCurvMask(r = -self.my * self.z0 / (self.my - 1), plane='y').apply(dfl)
+
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in %.2f sec' % t_func)
+        
+        return dfl
+    
+    
+class QuadCurvMask(Mask):
+    """
+    Quadratic curvature wavefront mask
+    add quadratic x and y term in 's' space 
+    
+    :param r: radius of curveture
+    :param plane: plane in which the curvature added
+    :param mask: the transfer function itself
+    """
+    def __init__(self, r, plane):
         Mask.__init__(self)
-        self.lx = np.inf
-        self.ly = np.inf
-        self.mask = None
+        self.r = r 
+        self.plane = plane 
+        # self.mask = None 
+    
+    def get_mask(self, dfl):
+        """
+        'get_mask' method for QuadCurvMask class      
+        
+        TODO write a description 
+        """        
+        self.copy_grid(dfl)
+       
+        x, y = np.meshgrid(dfl.grid_x(), dfl.grid_y())
+        if self.plane == 'xy' or self.plane == 'yx':
+            arg2 = x ** 2 + y ** 2
+        elif self.plane == 'x':
+            arg2 = x ** 2
+        elif self.plane == 'y':
+            arg2 = y ** 2
+        else:
+            raise ValueError("'plane' should be in 'x', 'y'")
 
+        _logger.debug(ind_str + 'calculating mask in "{}" domain'.format(dfl.domain_z))     
+            
+        if self.domain_z == 'f':
+            k = 2 * np.pi /dfl.grid_kz() 
+            self.msk = np.ones(dfl.shape(), dtype=complex128)
+    
+            if np.size(self.r) == 1:
+                self.msk *= np.exp(-1j * k[:, np.newaxis, np.newaxis] / 2 * arg2[np.newaxis, :, :] / self.r) #H = exp(-i * k / 2 * (x^2 + y^2))
+            elif np.size(self.r) == dfl.Nz():
+                self.msk *= np.exp(-1j * k[:, np.newaxis, np.newaxis] / 2 * arg2[np.newaxis, :, :] / self.r[:, np.newaxis, np.newaxis])
+            else:
+                raise ValueError('wrong dimensions of radius of curvature')    
+
+        elif self.domain_z == 't':
+            k = 2 * np.pi / dfl.xlamds
+            self.msk = np.ones(dfl.shape()[1:3], dtype=complex128)
+            if np.size(self.r) == 1:
+                self.msk = np.exp(-1j * k / 2 * arg2 / self.r)
+            elif np.size(self.r) == dfl.Nz():
+                self.msk = np.exp(-1j * k / 2 * arg2[np.newaxis, :, :] / self.r[:, np.newaxis, np.newaxis])
+            else:
+                raise ValueError('wrong dimensions of radius of curvature')
+        else:
+            raise ValueError("domain_z should be in 'f', 't'")
+        _logger.debug(ind_str + 'transfer function mask shape {}'.format(self.msk.shape))         
+    
+        return self.msk
+    
     def apply(self, dfl):
-        if self.mask is None:
-            self.get_mask(dfl)
-        mask_idx = np.where(self.mask == 0)
+        """
+        'apply' method for QuadCurvMask class      
+        
+        get the mask using 'get_mask' method
+        convert the field to a spatial domain
+        multiply the mask and the field
+        convert the field to the original domain
+        """
+        domains = dfl.domain_z, dfl.domain_xy
+        
+        self.domain_x = 's'
+        self.domain_y = 's'
+        if self.domain_z is None:
+            self.domain_z = dfl.domain_z
+        
+        _logger.debug('curving radiation wavefront by {}m in {} domain'.format(self.r, self.domain_z))
+        
+        if np.size(self.r) == 1:
+            if self.r == 0:
+                raise ValueError('radius of curvature cannot be zero')
+            elif self.r == np.inf:
+                _logger.debug(ind_str + 'radius of curvature is infinite, skipping')
+                return
+            else:
+                pass
+            
+        if self.msk is None:
+            self.get_mask(dfl) 
+    
+        dfl.to_domain(self.domain_z + 's')
+        dfl.fld *= self.msk 
+        dfl.to_domain(domains) 
 
-        # dfl_out = deepcopy(dfl)
-        dfl_energy_orig = dfl.E()
-        dfl.fld[:, mask_idx[0], mask_idx[1]] = 0
+        return dfl
 
-        if dfl_energy_orig == 0:
-            _logger.warn(ind_str + 'dfl_energy_orig = 0')
-        elif dfl.E() == 0:
-            _logger.warn(ind_str + 'done, %.2f%% energy lost' % (100))
-        else:
-            _logger.info(ind_str + 'done, %.2f%% energy lost' % ((dfl_energy_orig - dfl.E()) / dfl_energy_orig * 100))
-        # tmp_fld = dfl.fld[:,idx_x1:idx_x2,idx_y1:idx_y2]
+class LensMask(Mask):
+    """
+    A thin ideal Lens mask
+
+    :param fx: focus length in x direction, [m]
+    :param fy: focus length in y direction, [m]
+    """
+    def __init__(self, fx=np.inf, fy=np.inf):
+        Mask.__init__(self)
+        self.fx = fx
+        self.fy = fy
+              
+    def apply(self, dfl):
+        _logger.info('apply the lens mask')
+        domains = dfl.domains()
+
+        if self.msk is None:
+            self.get_mask(dfl)
+                
+        dfl.to_domain('fs')
+        dfl.fld *= self.msk
+        dfl.to_domain(domains)
+        
         return dfl
+    
+    def get_mask(self, dfl):
 
+        _logger.info('get the lens mask')        
+        H_fx = QuadCurvMask(r=self.fx, plane='x').get_mask(dfl)        
+        H_fy = QuadCurvMask(r=self.fy, plane='y').get_mask(dfl)
+        self.msk = H_fx * H_fy
+      
+        return self.msk
+    
+class ApertureRectMask(Mask):
+    """
+     Applies a rectangular appertire for a field
+     
+    :param lx: horizonatal size of the aperture, [m]
+    :param ly: vertical size of the aperture, [m]
+    :param cx: x coprdinate coordinate of the aperture center, [m] 
+    :param cy: y coprdinate coordinate of the aperture center, [m] 
+    :mask: the rectangular aperture transfer function
+    """
+    def __init__(self, lx=np.inf, ly=np.inf, cx=0, cy=0):
+        Mask.__init__(self)
+        self.lx = lx
+        self.ly = ly
+        self.cx = cx
+        self.cy = cy
+        # self.mask = None
     def get_mask(self, dfl):
         """
-        model rectangular aperture to the radaition in either domain
+        model a rectangular aperture to the radaition in 's' domain
         """
         _logger.info('applying square aperture to dfl')
-
+        
+        self.copy_grid(dfl)
+            
         if np.size(self.lx) == 1:
             self.lx = [-self.lx / 2, self.lx / 2]
         if np.size(self.ly) == 1:
             self.ly = [-self.ly / 2, self.ly / 2]
         _logger.debug(ind_str + 'ap_x = {}'.format(self.lx))
         _logger.debug(ind_str + 'ap_y = {}'.format(self.ly ))
+        
+        idx_x = np.where((dfl.grid_x() >= self.lx[0]) & (dfl.grid_x() <= self.lx[1]))[0]
+        idx_x1 = idx_x[0]# + 1 #magic number
+        idx_x2 = idx_x[-1]  
 
-        idx_x = np.where((dfl.scale_x() >= self.lx[0]) & (dfl.scale_x() <= self.lx[1]))[0]
-        idx_x1 = idx_x[0]
-        idx_x2 = idx_x[-1]
-
-        idx_y = np.where((dfl.scale_y() >= self.ly [0]) & (dfl.scale_y() <= self.ly [1]))[0]
-        idx_y1 = idx_y[0]
-        idx_y2 = idx_y[-1]
+        idx_y = np.where((dfl.grid_y() >= self.ly[0]) & (dfl.grid_y() <= self.ly[1]))[0]
+        idx_y1 = idx_y[0]# + 1 #magic number
+        idx_y2 = idx_y[-1]# + 1 #magic number
 
         _logger.debug(ind_str + 'idx_x = {}-{}'.format(idx_x1, idx_x2))
         _logger.debug(ind_str + 'idx_y = {}-{}'.format(idx_y1, idx_y2))
 
-        self.mask = np.zeros_like(dfl.fld[0, :, :])
-        self.mask[idx_y1:idx_y2, idx_x1:idx_x2] = 1
-        return self.mask
+        self.msk = np.zeros_like(dfl.fld[0, :, :])
+        self.msk[idx_y1:idx_y2, idx_x1:idx_x2] = 1
+        _logger.debug(ind_str + 'transfer function mask shape {}'.format(self.msk.shape))         
 
-    def __mul__(self, other):
-        print("mul")
-        m = RectMask()
-        if other.__class__ in [RectMask, ] and self.mask is not None and other.mask is not None:
-            m.mask = self.mask * other.mask
-            return m
+        return self.msk
+    
+    def apply(self, dfl):
+        
+        domains = dfl.domain_z, dfl.domain_xy
+        self.domain_x = 's'
+        self.domain_y = 's'
+        if self.domain_z is None:
+            self.domain_z = dfl.domain_z
+        
+        dfl.to_domain(self.domain_z + 's')
 
+        if self.msk is None:
+            self.get_mask(dfl)
+                
+        mask_idx = np.where(self.msk == 0)
+
+        dfl_energy_orig = dfl.E()
+        dfl.fld[:, mask_idx[0], mask_idx[1]] = 0
 
-class DriftMask(Mask):
+        if dfl_energy_orig == 0:
+            _logger.warn(ind_str + 'dfl_energy_orig = 0')
+        elif dfl.E() == 0:
+            _logger.warn(ind_str + 'done, %.2f%% energy lost' % (100))
+        else:
+            _logger.info(ind_str + 'done, %.2f%% energy lost' % ((dfl_energy_orig - dfl.E()) / dfl_energy_orig * 100))
+        
+        dfl.to_domain(domains) 
+        return dfl
 
-    def __init__(self, l, mx, my):
+class ApertureEllipsMask(Mask):
+    """
+     Applies a rectangular appertire for a field
+     
+    :param ax: ellipse x main axis, [m]
+    :param ay: ellipse y main axis, [m]
+    :param cx: ellipse x coordinate of center, [m] 
+    :param cy: ellipse y coordinate of center, [m]  
+    :mask: the elliptical aperture transfer function
+    """
+    def __init__(self, ax=np.inf, ay=np.inf, cx=0, cy=0):
         Mask.__init__(self)
-        self.l = l
-        self.mx = mx
-        self.my = my
+        self.ax = ax
+        self.ay = ay
+        self.cx = cx
+        self.cy = cy
+        # self.mask = None 
+    
+    def ellipse(self, dfl):    
+        x, y = np.meshgrid(dfl.grid_x(), dfl.grid_y())
+        xp =  (x - self.cx)*np.cos(pi) + (y - self.cy)*np.sin(pi)
+        yp = -(x - self.cx)*np.sin(pi) + (y - self.cy)*np.cos(pi)
+        return (2*xp/self.ax)**2 + (2*yp/self.ay)**2
+    
+    def apply(self, dfl):
+        """
+        apply elliptical aperture to the radaition in 's' domain
+        """
+        
+        _logger.info('applying elliptical aperture to dfl')
+        _logger.debug(ind_str + 'ap_x = {}'.format(self.ax) + 'cx = {}'.format(self.cx))
+        _logger.debug(ind_str + 'ap_y = {}'.format(self.ay) + 'cy = {}'.format(self.cy))
 
+        domains = dfl.domain_z, dfl.domain_xy
+        self.domain_x = 's'
+        self.domain_y = 's'
+        if self.domain_z is None:
+            self.domain_z = dfl.domain_z
+        
+        dfl.to_domain(self.domain_z + 's')
+        if self.msk is None:
+            self.get_mask(dfl)
+        
+        mask_idx = np.where(self.msk == 0)
+
+        dfl_energy_orig = dfl.E()
+        dfl.fld[:, mask_idx[0], mask_idx[1]] = 0
+        
+        if dfl_energy_orig == 0:
+            _logger.warn(ind_str + 'dfl_energy_orig = 0')
+        elif dfl.E() == 0:
+            _logger.warn(ind_str + 'done, %.2f%% energy lost' % (100))
+        else:
+            _logger.info(ind_str + 'done, %.2f%% energy lost' % ((dfl_energy_orig - dfl.E()) / dfl_energy_orig * 100))
+        
+        dfl.to_domain(domains) 
+        return dfl
+    
+    def get_mask(self, dfl):
+        
+        self.copy_grid(dfl)
+        
+        self.msk = np.zeros_like(dfl.fld[0, :, :])
+        self.msk[self.ellipse(dfl) <= 1] = 1
+        
+        return self.msk
+
+class PhaseDelayMask(Mask):
+    """
+    The function adds a phase shift to a fld object. The expression for the phase 
+    -- coeff[0] + coeff[1]*(w - w0)/1! + coeff[2]*(w - w0)**2/2! + coeff[3]*(w - w0)**3/3!
+    
+    :param: coeff 
+        coeff[0] =: measured in [rad]      --- phase
+        coeff[1] =: measured in [fm s ^ 1] --- group delay
+        coeff[2] =: measured in [fm s ^ 2] --- group delay dispersion (GDD)
+        coeff[3] =: measured in [fm s ^ 3] --- third-order dispersion (TOD)
+        ...
+    :param E_ph0:  energy with respect to which the phase shift is calculated
+    :mask: phase delay aperture transfer function
+    """
+    def __init__(self, coeff, E_ph0):
+        Mask.__init__(self)
+        self.coeff = coeff
+        self.E_ph0 = E_ph0
+        # self.mask = None
+        
     def apply(self, dfl):
-        dfl.prop_m(z=self.l, m=(self.mx, self.my))
+        
+        _logger.info('apply the frequency chirp')
+        domains = dfl.domains()
+        
+        if self.msk is None: 
+            self.get_mask(dfl)
+        
+        dfl.to_domain('f')
+        dfl.fld *= self.msk
+        dfl.to_domain(domains)
+        
+        _logger.info('done')
         return dfl
 
+    def get_mask(self, dfl):
 
-class LensMask(Mask):
+        _logger.info('get the frequency chirp mask')
+        
+        self.copy_grid(dfl)
+        
+        if self.E_ph0 == None:
+            w0 = 2 * np.pi * speed_of_light / dfl.xlamds
+    
+        elif self.E_ph0 == 'center':
+            _, k = np.mean([dfl.int_z(), dfl.grid_kz()], axis=(1))
+            w0 = speed_of_light * k
+    
+        elif isinstance(self.E_ph0, str) is not True:
+            w0 = 2 * np.pi * self.E_ph0 / h_eV_s
+    
+        else:
+            raise ValueError("E_ph0 must be None or 'center' or some number")
 
-    def __init__(self, fx, fy):
-        Mask.__init__(self)
-        self.fx = fx
-        self.fy = fy
+        w = dfl.grid_kz() * speed_of_light
+        delta_w = w - w0
+
+        _logger.debug('calculating phase delay')
+        _logger.debug(ind_str + 'coeffs for compression = {}'.format(self.coeff))
+
+        coeff_norm = [ci / (1e15) ** i / factorial(i) for i, ci in enumerate(self.coeff)]
+        coeff_norm = list(coeff_norm)[::-1]
+        _logger.debug(ind_str + 'coeffs_norm = {}'.format(coeff_norm))
+        delta_phi = np.polyval(coeff_norm, delta_w)
+
+        _logger.debug(ind_str + 'delta_phi[0] = {}'.format(delta_phi[0]))
+        _logger.debug(ind_str + 'delta_phi[-1] = {}'.format(delta_phi[-1]))
+
+        self.msk = np.exp(-1j * delta_phi)[:, np.newaxis, np.newaxis]
+
+        _logger.debug(ind_str + 'done')
+        
+        return self.msk
+        
+     
+class HeightErrorMask_1D(Mask):
+    """
+    Mask for simulating HeightProfile of highly polished mirror surface
 
+    :param hrms: [meters] height errors root mean square
+    :param length: [meters] length of the surface
+    :param points_number: number of points (pixels) at the surface
+    :param wavevector_cutoff: [1/meters] point on k axis for cut off small wavevectors (large wave lengths) in the PSD
+                                    (with default value 0 effects on nothing)
+    :param psd: [meters^3] 1d array; power spectral density of surface (if not specified, will be generated)
+            (if specified, must have shape = (points_number // 2 + 1, ), otherwise it will be cut to appropriate shape)
+    :param seed: seed for np.random.seed() to allow reproducibility
+    :return: HeightProfile object
+    """
+
+    def __init__(self, height_profile=None, hrms=0, axis='x', angle=np.pi * 2 / 180, seed=None):
+        Mask.__init__(self)
+        # self.mask = None
+        self.height_profile = height_profile 
+        self.hrms = hrms
+        self.axis = axis
+        self.angle = angle
+        self.seed = seed
+        
     def apply(self, dfl):
-        print("LENS APPLY fx_{}".format(self.fx))
-        dfl.curve_wavefront(r=self.fx, plane='x', domain_z=None)
+        
+        _logger.info('apply HeightProfile errors')
+        start = time.time()
+
+        if self.msk is None: 
+            self.get_mask(dfl)
+
+        dfl.fld *= self.msk
+        
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in {}'.format(t_func))
+
         return dfl
+        
+    def get_mask(self, dfl):
+        
+        self.copy_grid(dfl)
+        
+        dict_axes = {'z': 0, 'y': 1, 'x': 2}
+        dl = {0: dfl.dz, 1: dfl.dy, 2: dfl.dx}
+        
+        if isinstance(self.axis, str):
+            axis = dict_axes[self.axis]
+ 
+        n = dfl.fld.shape[axis]
+        eff_l = n * dl[axis] / np.sin(self.angle)
+        if self.height_profile is None:
+            if self.hrms is None:
+                _logger.error('hrms and height_profile not specified')
+                raise ValueError('hrms and height_profile not specified')
+            self.height_profile = HeightProfile()
+            self.height_profile = self.height_profile.generate_1d_profile(self.hrms, L=eff_l, N=n, seed=self.seed)
+        
+        elif self.height_profile.L != eff_l or self.height_profile.N != n:
+            if self.height_profile.L < eff_l:
+                _logger.warning(
+                    'provided height profile length {} is smaller than projected footprint {}'.format(height_profile.L,
+                                                                                                      eff_l))  # warn and pad with zeroes
+    
+            # interpolation of height_profile to appropriate sizes
+            _logger.info(ind_str + 'given height_profile was interpolated to length and '.format(dfl.shape()))
+            s = np.linspace(-eff_l / 2, eff_l / 2, n)
+            h = np.interp(s, height_profile.s, height_profile.h, right=height_profile.h[0], left=height_profile.h[-1])
+            self.height_profile = HeightProfile()
+            self.height_profile.points_number = dfl.fld.shape[axis]
+            self.height_profile.L = eff_l
+            self.height_profile.s = s
+            self.height_profile.h = h
+    
+        phase_delay = 2 * 2 * np.pi * np.sin(self.angle) * self.height_profile.h / dfl.xlamds
+        
+        if self.axis == 'x':
+            self.msk = np.exp(1j * phase_delay)[np.newaxis, np.newaxis, :]
+        elif self.axis == 'y':
+            self.msk = np.exp(1j * phase_delay)[np.newaxis, :, np.newaxis]
+        elif self.axis == 'z':
+            self.msk = np.exp(1j * phase_delay)[:, np.newaxis, np.newaxis]             
+        return self.msk
+   
+    
+class MirrorMask(Mask):
+    """
+    Class for simulating HeightProfile of highly polished mirror surface
+    
+    TODO
+    write documentation
+    add logging
+    """
+    def __init__(self, height_profile=None, hrms=0, angle=2*np.pi/180, plane='x', lx=np.inf, ly=np.inf, shape=(0, 0, 0)):
+        Mask.__init__(self, shape=shape)
+        self.height_profile = height_profile 
+        self.hrms = hrms #must have a size equals 2 
+        self.angle = angle
+        # self.mask = None
+        
+        if plane == 'x':
+            self.lx = lx/np.sin(self.angle)
+            self.ly = ly
+        elif plane == 'y':
+            self.lx = lx
+            self.ly = ly/np.sin(self.angle)
+        else:
+            raise ValueError(" 'plane' must be 'x' or 'y' ")
+
+    def get_mask(self, dfl):
+        _logger.info('getting HeightProfile errors')
+        
+        if self.msk is None:
+            heightErr_x = HeightErrorMask_1D(height_profile=self.height_profile, hrms=self.hrms, axis='x', angle=self.angle)
+            heightErr_x.get_mask(dfl) 
+            heightErr_y = HeightErrorMask_1D(height_profile=self.height_profile, hrms=self.hrms, axis='y', angle=self.angle)
+            heightErr_y.get_mask(dfl) 
+            RectApp = ApertureRectMask()
+            RectApp.lx = self.lx
+            RectApp.ly = self.ly           
+            RectApp.get_mask(dfl)
+            self.msk = heightErr_x.msk * heightErr_y.msk * RectApp.msk
+        return self.msk
+    
+    def apply(self, dfl):
+        
+        _logger.info('apply HeightProfile errors')
+        start = time.time()
+
+        if self.msk is None: 
+            self.get_mask(dfl)
+
+        dfl.fld *= self.msk
+        
+        t_func = time.time() - start
+        _logger.debug(ind_str + 'done in {}'.format(t_func))
+
+        
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
\ No newline at end of file
diff --git a/ocelot/rad/undulator_params.py b/ocelot/rad/undulator_params.py
index 642c1e7d..f4d2c4c6 100644
--- a/ocelot/rad/undulator_params.py
+++ b/ocelot/rad/undulator_params.py
@@ -16,6 +16,22 @@ def lambda2eV(Lambda):
 def eV2lambda(Ephoton):
     Lambda = h_eV_s*speed_of_light/Ephoton
     return Lambda
+    
+def k2lambda(k):
+    Lambda = 2 * np.pi / k
+    return Lambda
+    
+def lambda2k(Lambda):
+    k = 2 * np.pi / Lambda
+    return k
+
+def k2angle(k, Lambda):
+    angle = k * Lambda / 2 / np.pi
+    return angle
+
+def angle2k(angle, Lambda):
+    k =  2 * np.pi * angle / Lambda
+    return k
 
 def Ephoton2K(Eph, lu=0.04, Eeb=14):
     gamma = Eeb/m_e_GeV
diff --git a/ocelot/utils/launcher.py b/ocelot/utils/launcher.py
index e5bd8728..34f03e76 100644
--- a/ocelot/utils/launcher.py
+++ b/ocelot/utils/launcher.py
@@ -115,7 +115,10 @@ def prepare(self):
     def launch(self):
         t1 = time.time()
         _logger.info('launching mpi job')
-        command = 'mkdir -p '+ self.dir + '; ' + 'cd '+ self.dir + '; '+ "`which mpirun` " + str(self.mpiParameters) + " " + self.program + self.argument
+        if hasattr(self, 'command'):
+            command = self.command #command override
+        else:
+            command = 'mkdir -p '+ self.dir + '; ' + 'cd '+ self.dir + '; '+ "`which mpirun` " + str(self.mpiParameters) + " " + self.program + " " + self.argument
         _logger.debug(ind_str + 'launcher command "{}"'.format(command))
         # print (command)
         os.system(command)
@@ -128,6 +131,190 @@ def collect(self, inputDir, outputDir, pattern = "*"):
         #os.system('cp ' + inputDir + pattern + ' ' + outputDir)
         pass
 
+######################################################################
+#
+# Current issues with MpiQueueLauncher:
+# * Need to check that self.dir is valid directory with permissions
+#   enabling write (or that directory can at least created under this name).
+#   If needed, create directory not using 'mkdir' shell command but
+#   using Python-embedded mkdir (should result in better error handling).
+# * When update_job_state is called immediately after submitting the job,
+#   it does not work: It prints the line
+#   "unable to extract job status from 'sacct' output, exit code was: 0".
+
+class MpiQueueLauncher(Launcher):
+    def __init__(self):
+        self.id = ''
+        self.program = "" # old
+        self.argument = "" # old
+        self.dir = None # force user to assign it (done for instance in run_genesis of genesis2 adaptor)
+        self.nproc = 0
+        self.mpiParameters = "" # old
+
+        self.jobscript_template='T_run_g2.sh' # as of now, the templates reside in the same directory as MpiQueueLauncher() source code
+        self.jobscript_setup=True
+
+        self.jobpartition='maxwell'
+        self.jobnodes=2
+        self.jobntaskspernode=32
+        self.jobname=None
+        self.launch_wait = True
+        ### params of running job
+        self.jobid=-1        # assigned on job submission
+        self.jobid_valid=False
+        self.jobstate=''     # updated in 'update_job_state'
+        self.jobtime=''      # updated in 'update_job_state'
+
+
+    def prepare(self):
+        return False
+
+
+    def submit(self):
+        # Check that working directory is assigned before proceeding
+        # OCELOT GENESIS v2 adaptor assignes .dir variable, before running
+        # job, so this is mainly issue when used by other callers...
+        if self.dir is None:
+            _logger.error('*** No directory for job execution specified, aborting ***')
+            return
+
+        _logger.info('preparing job')
+
+        # deploy SLURM job script
+        # generate output dir for stdout and stderr
+        # delete any flag files that might still be there for an earlier run (for example, the previous stage in a series of stages)
+        jobscript='./run.sh' # default job script name in job working directory (can be overwritten, if needed)
+        if self.jobscript_setup:
+            jobscript_t=os.path.dirname(__file__)+'/'+self.jobscript_template
+            setupcmd='cp "'+jobscript_t+'" "'+self.dir +'/'+jobscript+'"; mkdir -p '+self.dir+'/jobout; rm -f '+self.dir+'/flag.start '+self.dir+'/flag.finish'
+            _logger.debug(ind_str + 'setup command "{}"'.format(setupcmd))
+            os.system(setupcmd)
+        else:
+            _logger.debug(ind_str + 'setup command disabled by user')
+            jobscript=self.jobscript_template
+        #
+        # assemble cmd line
+        # !no quotes around strings, the submission of the args as list elements ensures that for instance strings with spaces in them are treated as single arguments!
+        _logger.info('submitting job to MAXWELL cluster queue 1/2 (assembling cmd line)')
+        args=['sbatch', '--parsable']
+        if self.jobname is not None:
+            args.append('--job-name={0:s}'.format(str(self.jobname)))
+        args.append('--partition={0:s}'.format(self.jobpartition))
+        args.append('--nodes={0:d}'.format(self.jobnodes))
+        args.append('--ntasks-per-node={0:d}'.format(self.jobntaskspernode))
+        args.append(jobscript)
+        _logger.info('submitting job to MAXWELL cluster queue 2/2 (submitting)')
+        _logger.debug('running command: {0:s} (remark/TODO: this does not print quotes around the arguments)'.format(" ".join(args)))
+        p=subprocess.Popen(args, cwd=self.dir, stdout=subprocess.PIPE)
+        (out,err)=p.communicate()
+        rc=p.returncode # get exit code of 'sbatch' call (but not used as of now)
+        _logger.debug('exit code of command: {0}'.format(str(rc)))
+        # print("output:", out)
+        # As of 2021-Jan, success job submission on maxwell will return jobid in format: b'6759516\n'
+        try:
+            tstr=out.rstrip()
+            self.jobid=int(tstr)  # retain job id for future reference
+            self.jobid_valid=True
+            _logger.info('job submitted: jobid={0}, sbatch returned status {1}'.format(str(self.jobid),str(rc)))
+        except ValueError:
+            # unexpected output (format) from sbatch (or on error: no output at all)
+            self.jobid_valid=False
+            _logger.info('unclear if job submission successful, sbatch returned status {0}'.format(str(rc)))
+            return False # job submission not successful
+        #
+        return True # true => job submission successful
+
+####
+    def update_job_state(self):
+        dbg=False
+        if(self.jobid_valid==False):
+            print('error: update_job_state: jobid is not valid. Was job submission successful?')
+            return False
+
+        p = subprocess.Popen(['sacct', '--parsable2', '--noheader', '--format', 'JobID,State,Partition,AllocCPUs,Elapsed', '-j', str(self.jobid)], stdout=subprocess.PIPE)
+
+        # process output of 'sacct' command (typically multiple lines)
+        gotit=False
+        while (gotit==False):
+            # example for typical format: l='6761134|COMPLETED|maxwell|80|00:02:48'
+            l=p.stdout.readline()
+            if not l:
+                break
+
+            l=l.decode()
+            l=l.rstrip()
+            print('update_job_state dbg: considering acct output line "{0}"'.format(l))
+            ls=l.split('|')
+
+            # expecting 5 fields
+            nele=len(ls)
+            if nele!=5:
+                print('error: was expecting 5 fields from sacct output')
+                break # return
+
+            my_jobstate=ls[1]
+            my_jobtime=ls[4]
+            part=ls[2]
+            # only one of the lines from 'sacct' cmd has partition info => this one we want, skip all others
+            if not part:
+                if dbg:
+                    print('no partition id found, skipping to next line')
+                continue
+            gotit=True
+
+        p.wait(timeout=10) # exit code is only available after termination of sub-process
+        rc=p.returncode # get exit code of 'sacct' call (not used as of now)
+        if gotit:
+            if dbg:
+                print('jobtime:'+my_jobtime+', jobstate:'+my_jobstate)
+            self.jobtime=my_jobtime
+            self.jobstate=my_jobstate
+        else:
+            print("unable to extract job status from 'sacct' output, exit code was: {0}".format(rc))
+
+
+    def is_complete(self):
+        # 1) query scheduler and update variables in class (status codes aren't evaluated yet)
+        self.update_job_state()
+
+        # 2) check the status file generated in the job script
+        flagfile=self.dir+'/flag.finish'
+        if (os.path.isfile(flagfile)==True):
+            return True
+        return False
+
+
+    def wait_for_completion(self,verbose=False):
+        flagfile=self.dir+'/flag.finish'
+        _logger.info('waiting for job completion, polling file "{}"'.format(flagfile))
+        while True:
+            is_complete=self.is_complete()
+            if verbose:
+                print('job {0}: state={1}, runtime={2}, is_complete={3}'.format(self.jobid, self.jobstate, self.jobtime, is_complete))
+            if(is_complete):
+                break
+            time.sleep(10) # <== won't wait if the job is already complete
+####
+    # Simple interface if you don't plan to run multiple job in parallel
+    # Also to support code built around MpiLauncher()
+    def launch(self):
+        t1 = time.time()
+        self.submit()
+        if self.launch_wait==False:
+            return
+        self.wait_for_completion()
+        t2 = time.time()
+        _logger.debug(ind_str + 'execution time {:} sec'.format(t2 - t1))
+            
+    # collect data to directory
+    def collect(self, inputDir, outputDir, pattern = "*"):
+        #print 'collecting results'
+        #os.system('cp ' + inputDir + pattern + ' ' + outputDir)
+        pass
+
+######################################################################
+
+
 class NewLauncher(Launcher):
     '''
     for MOGA, tmp?
diff --git a/ocelot/utils/xfel_utils.py b/ocelot/utils/xfel_utils.py
index dd3e8c2f..50746cdb 100644
--- a/ocelot/utils/xfel_utils.py
+++ b/ocelot/utils/xfel_utils.py
@@ -136,7 +136,7 @@ def dfl_hxrss_filt(dfl, trf, s_delay, st_cpl=1, enforce_padn=None, res_per_fwhm=
         if st_cpl:
             dfl_st_cpl(dfl, trf.thetaB)
 
-        dfl_shift_z(dfl, s_delay, set_zeros=0)
+        dfl_shift_s(dfl, s_delay, set_zeros=0)
         _logger.debug(ind_str + 'shape_before '+str(dfl.shape()))
         dfl_pad_z(dfl, -padn)
         _logger.debug(ind_str + 'shape_after '+str(dfl.shape()))
@@ -154,7 +154,7 @@ def dfl_hxrss_filt(dfl, trf, s_delay, st_cpl=1, enforce_padn=None, res_per_fwhm=
         dfl.fft_z(method=fft_method, nthread=multiprocessing.cpu_count())
         if st_cpl:
             dfl_st_cpl(dfl, trf.thetaB)
-        dfl_shift_z(dfl, s_delay, set_zeros=0)
+        dfl_shift_s(dfl, s_delay, set_zeros=0)
         dfl_pad_z(dfl, -padn)
 
         t_func = time.time() - start
@@ -265,8 +265,10 @@ def create_fel_lattice(und_N = 35,
         cell = (und, d1, qd, phs, d2, und, d1, qf, phs, d2) 
         extra_fodo = (und, d2, qfh)
         lat = (und, d1, qf, phs, d2) + cell_N * cell + cell_N_last * (und,)
-
-    return (MagneticLattice(lat), extra_fodo, cell)
+    
+    lat = MagneticLattice(lat)
+    
+    return (lat, extra_fodo, cell)
 
 def create_fel_lattice_tmp(und_N = 34,
                     und_L = 5,
@@ -322,7 +324,7 @@ def create_fel_lattice_tmp(und_N = 34,
 
 def create_fel_beamline(beamline = 'sase1', inters_phi=0, inters_K = "K_und"):
     if beamline in ['sase1', 1, 'sase2', 2, 'EuXFEL_SASE1', 'EuXFEL_SASE2']:
-        return create_fel_lattice(und_N = 35,
+        return create_fel_lattice(und_N = 37,
                         und_L = 5-0.04,
                         und_l = 0.04,
                         und_Kx = 0,
@@ -334,6 +336,7 @@ def create_fel_beamline(beamline = 'sase1', inters_phi=0, inters_K = "K_und"):
                         quad_K = 0,
                         phs_L = 0.0,
                         quad_start = 'd',
+                        beamline_name = beamline
                             )
     elif beamline in ['sase3', 3, 'EuXFEL_SASE3']:
         return create_fel_lattice(und_N = 21,
@@ -348,6 +351,7 @@ def create_fel_beamline(beamline = 'sase1', inters_phi=0, inters_K = "K_und"):
                         quad_K = 0,
                         phs_L = 0.0,
                         quad_start = 'd',
+                        beamline_name = beamline
                             )
     else:
         raise ValueError('Unknown beamline')
@@ -698,3 +702,68 @@ def run(self):
             s3d.mesh_size = (int(g('ncar')), int(g('ncar')))
             s3d.g = g
             return s3d, None
+
+def calc_ebeam_modulation_in_undulator(z=None, #scale along undulator
+                                       s=None, #scale along pulse
+                                       laser_E=0.003, #laser pulse energy [J]
+                                       laser_t_fwhm=5e-15, #laser pulse duration fwhm [s]
+                                       laser_wavelength=8e-7, #laser wavelength [m]
+                                       laser_Zr=0.7, #laser rayleigh length [m]
+                                       und_Nperiods=2, #number of unudlaor periods
+                                       und_period=0.7, #undulator period length [m]
+                                       beam_gamma=22505, #electron beam Lorentz factor
+                                       detuning=-0.3, #undulator detuning
+                                       laser_phase_shift=0, #shift of laser phase [rad]
+                                       laser_pulse_shift=0, #shift of laser pulse [rad]
+                                       ):
+    '''
+    calculations of electron beam molulation in an undulator
+    based on A. A. Zholents and M. S. Zolotorev, New Journal of Physics 10, 025005 (2008).
+    
+    z=None, #scale along undulator
+    s=None, #scale along pulse
+    laser_E=0.003, #laser pulse energy [J]
+    laser_t_fwhm=5e-15, #laser pulse duration fwhm [s]
+    laser_wavelength=8e-7, #laser wavelength [m]
+    laser_Zr=0.7, #laser rayleigh length [m]
+    und_Nperiods=2, #number of unudlaor periods
+    und_period=0.7, #undulator period length [m]
+    beam_gamma=22505, #electron beam Lorentz factor
+    detuning=-0.3, #undulator detuning
+    laser_phase_shift=0, #shift of laser phase [rad]
+    laser_pulse_shift=0, #shift of laser pulse [rad]
+    
+    '''
+
+    if z == None:
+        z = np.linspace(-0.5,0.5,50)[:,None]
+    if s == None:
+        s = np.linspace(-2, 2, 300)[None,:]
+    s = s - laser_pulse_shift / und_Nperiods / 2 / np.pi
+    
+    
+    P0 = I_Alfven * m_e_kg * speed_of_light**2 / q_e
+    und_K = (2 * (2 * beam_gamma**2 * laser_wavelength / und_period - 1))**0.5
+    
+    ksi = und_K**2 / (2 + und_K**2)
+    q = und_Nperiods * und_period / laser_Zr
+    
+    sig_s = 2**0.5 * speed_of_light * laser_t_fwhm / (2.35 * und_Nperiods * laser_wavelength)
+    
+    w0 = (laser_Zr * laser_wavelength / np.pi)**0.5
+    #print(w0)
+    x0 = und_K * und_period / (2 * np.pi * beam_gamma * w0)
+    #print(x0)
+    JJ = scipy.special.j0(ksi/2) - scipy.special.j1(ksi/2)
+    
+    dgam_dz = (16*np.pi * laser_E * und_Nperiods * ksi / laser_t_fwhm / P0)**0.5 * JJ \
+        * (q / (1 + q**2 * z**2))**0.5 \
+        * np.cos(laser_phase_shift + .123 + 2 * np.pi * detuning * z + np.arctan(q * z) - 2 * np.pi * und_Nperiods * s - x0**2 * np.sin(2 * np.pi * z)**2 / (1 + q**2 * z**2)) \
+        * np.exp(-x0**2 * np.sin(2 * np.pi * z)**2/(1 + q**2 * z**2)) * np.exp(-(z - s)**2 / (2 * sig_s**2))
+    
+    dgam = np.sum(dgam_dz, axis=0) * (z[1] - z[0])
+    s_um = s[0,:] * und_Nperiods * laser_wavelength * 1e6
+    z_m = z[:,0]
+    
+    #dgam_gam_ds = np.diff(dgam)/np.diff(s_um)
+    return(s_um, z_m, dgam_dz, dgam)
\ No newline at end of file


Test patch:
diff --git a/demos/other/ocelot_logging_tests.py b/demos/other/ocelot_logging_tests.py
new file mode 100644
index 00000000..47b03b75
--- /dev/null
+++ b/demos/other/ocelot_logging_tests.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Nov 26 12:22:32 2019
+
+@author: sserkez
+
+getLogger() returns a reference to a logger instance with the specified name if it is provided, or root if not. 
+The names are period-separated hierarchical structures. Multiple calls to getLogger() with the same name will return a reference 
+to the same logger object. Loggers that are further down in the hierarchical list are children of loggers higher up in the list. 
+For example, given a logger with a name of foo, loggers with names of foo.bar, foo.bar.baz, and foo.bam are all descendants of foo.
+
+Loggers have a concept of effective level. If a level is not explicitly set on a logger, the level of its parent is used instead 
+as its effective level. If the parent has no explicit level set, its parent is examined, and so on - all ancestors are searched 
+until an explicitly set level is found. The root logger always has an explicit level set (WARNING by default). 
+When deciding whether to process an event, the effective level of the logger is used to determine whether the event is passed 
+to the logger’s handlers.
+
+Child loggers propagate messages up to the handlers associated with their ancestor loggers. 
+Because of this, it is unnecessary to define and configure handlers for all the loggers an application uses. 
+It is sufficient to configure handlers for a top-level logger and create child loggers as needed. 
+(You can, however, turn off propagation by setting the propagate attribute of a logger to False.)
+
+"""
+
+import logging
+
+import ocelot
+from ocelot.common.ocelog import *
+
+print(__name__)
+
+#----------------------
+# SETTING UP LOGGER1
+
+_logger1 = logging.getLogger('logger0.FirstLoggerName')
+#_logger1.propagate=0
+#print('Logger1 handlers before cleaning: ',_logger1.handlers)
+_logger1.handlers = []
+#print('Logger1 handlers after cleaning: ',_logger1.handlers)
+ 
+
+   
+ch1 = logging.StreamHandler()
+ch1.setLevel(logging.DEBUG)
+#log_console_format = logging.Formatter("[%(levelname)-8s] %(message)s")
+#cf1 = log_console_format
+#ch1.setFormatter(cf1)
+_logger1.addHandler(ch1) #added Console handler
+
+
+fh1 = logging.FileHandler('testlogger1.log')
+fh1.setLevel(logging.DEBUG)
+log_file_format = '%(asctime)s - [%(levelname)-8s] - %(message)s - %(name)s - %(filename)s:%(lineno)d'
+ff1 = logging.Formatter(log_file_format)
+fh1.setFormatter(ff1)
+_logger1.addHandler(fh1) #added File handler
+print('Logger1 file handler will write to {}'.format(fh1.baseFilename))
+print('Logger1 handlers after adding custom handlers: ',_logger1.handlers)
+
+#----------------------
+# SETTING UP LOGGER2
+
+_logger2 = logging.getLogger('logger0.SecondLoggerName')
+#_logger2.propagate=1
+_logger2.handlers = []
+
+
+ch2 = logging.StreamHandler()
+ch2.setLevel(logging.DEBUG)
+cf2 = logging.Formatter("[%(levelname)-8s] %(message)s")
+ch2.setFormatter(cf2)
+_logger2.addHandler(ch2)
+
+fh2 = logging.FileHandler('testlogger2.log')
+fh2.setLevel(logging.DEBUG)
+log_file_format = '%(asctime)s - [%(levelname)-8s] - %(message)s - %(name)s - %(filename)s:%(lineno)d'
+ff1 = logging.Formatter(log_file_format)
+fh2.setFormatter(ff1)
+_logger2.addHandler(fh2)
+print('Logger2 file handler will write to {}'.format(fh2.baseFilename))
+
+#----------------------
+# SETTING UP LOGGER LEVELS
+
+
+# logging levels: [DEBUG, INFO, WARNING, ERROR, CRITICAL, or a number, e.g. debug is 10, info is 12 etc..]
+_logger1.setLevel(logging.INFO) 
+_logger2.setLevel(logging.DEBUG)
+ocelog.setLevel(logging.DEBUG) #ocelog is a global logger
+
+
+#----------------------
+# SAMPLE OUTPUT
+
+
+_logger1.critical('logger_1_CRITICAL')
+_logger1.error('logger_1_ERROR')
+_logger1.warning('logger_1_WARNING')
+_logger1.info('logger_1_INFO')
+_logger1.debug('logger_1_DEBUG')
+
+
+_logger2.critical('logger_2_CRITICAL')
+_logger2.error('logger_2_ERROR')
+_logger2.warning('logger_2_WARNING')
+_logger2.info('logger_2_INFO')
+_logger2.debug('logger_2_DEBUG')
+
+
+ocelog.critical('ocelog_CRITICAL')
+ocelog.error('ocelog_ERROR')
+ocelog.warning('ocelog_WARNING')
+ocelog.info('ocelog_INFO')
+ocelog.debug('ocelog_DEBUG')
+ocelog.log(5, 'log level 5')
+ocelog.log(15, 'log level 15')
+ocelog.log(25, 'log level 25')
\ No newline at end of file