lidar_correction_ghk.py

Mon, 28 Jan 2019 11:21:13 +0100

author
Volker Freudenthaler <volker.freudenthaler@lmu.de>
date
Mon, 28 Jan 2019 11:21:13 +0100
changeset 34
548e14cb9c21
parent 28
79fa4a41420f
permissions
-rw-r--r--

updated Improvements_of_lidar_correction_ghk_ver.0.9.8_190125.pdf

# -*- coding: utf-8 -*-
"""
Copyright 2016, 2019 Volker Freudenthaler

Licensed under the EUPL, Version 1.1 only (the "Licence").

You may not use this work except in compliance with the Licence.
A copy of the licence is distributed with the code. Alternatively, you may obtain
a copy of the Licence at:

https://joinup.ec.europa.eu/community/eupl/og_page/eupl

Unless required by applicable law or agreed to in writing, software distributed
under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the Licence for the specific language governing
permissions and limitations under the Licence.

Equation reference: http://www.atmos-meas-tech-discuss.net/amt-2015-338/amt-2015-338.pdf
With equations code from Appendix C
Python 3.7, seaborn 0.9.0

Code description:

From measured lidar signals we cannot directly determine the desired backscatter coefficient (F11) and the linear depolarization ratio (LDR)
because of the cross talk between the channles and systematic errors of a lidar system.
http://www.atmos-meas-tech-discuss.net/amt-2015-338/amt-2015-338.pdf provides an analytical model for the description of these errors,
with which the measured signals can be corrected.
This code simulates the lidar measurements with "assumed true" model parameters from an input file, and calculates the correction parameters (G,H, and K).
The "assumed true" system parameters are the ones we think are the right ones, but in reality these parameters probably deviate from the assumed truth due to
uncertainties. The uncertainties of the "assumed true" parameters can be described in the input file. Then this code calculates the lidar signals and the
gain ratio eta* with all possible combinations of "errors", which represents the distribution of "possibly real" signals, and "corrects" them with the "assumed true"
GHK parameters (GT0, GR0, HT0, HR0, and K0) to derive finally the distributions of "possibly real" linear depolarization ratios (LDRcorr),
which are plotted for five different input linear depolarization ratios (LDRtrue). The red bars in the plots represent the input values of LDRtrue.
A complication arises from the fact that the correction parameter K = eta*/eta (Eq. 83) can depend on the LDR during the calibration measurement, i.e. LDRcal or aCal
in the code (see e.g. Eqs. (103), (115), and (141); mind the mistake in Eq. (116)). Therefor values of K for LDRcal = 0.004, 0.2, and 0.45 are calculated for
"assumed true" system parameters and printed in the output file behind the GH parameters. The full impact of the LDRcal dependent K can be considered in the error
calculation by specifying a range of possible LDRcal values in the input file. For the real calibration measurements a calibration range with low or no aerosol
content should be chosen, and the default in the input file is a range of LDRcal between 0.004 and 0.014 (i.e. 0.009 +-0.005).

Tip: In case you run the code with Spyder, all output text and plots can be displayed together in an IPython console, which can be saved as an html file.

Ver. 0.9.8: - for details, see "Improvements_of_lidar_correction_ghk_ver.0.9.8_190124.pdf"
    - correct calculation of Eta for cleaned anaylsers considering the combined transmission Eta = (TaT* TiT)(1 + cos2RotaT * DaT * DiT) and (TaR * TiR)(1 + cos2RotaR * DaR * DiR) according to the papers supplement Eqs. (S.10.10.1) ff
	- ND-filters can be added for the calibration measurements in the transmitted (TCalT) and the reflected path (TCalR) in order to include their uncertainties in the error calculation.
    - includes the simulation of signal noise
"""
# Comment:  The code might works with Python 2.7  with the help of following line, which enables Python2 to correctly interpret the Python 3 print statements.
from __future__ import print_function
# !/usr/bin/env python3

import os
import sys

import numpy as np

# Comment: the seaborn library makes nicer plots, but the code works also without it.
try:
    import seaborn as sns

    sns_loaded = True
except ImportError:
    sns_loaded = False

import matplotlib.pyplot as plt
# from time import clock # python 2
from timeit import default_timer as clock

# from matplotlib.backends.backend_pdf import PdfPages
# pdffile = '{}.pdf'.format('path')
# pp = PdfPages(pdffile)
## pp.savefig can be called multiple times to save to multiple pages
# pp.savefig()
# pp.close()

from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_target):
    old_target, sys.stdout = sys.stdout, new_target  # replace sys.stdout
    try:
        yield new_target  # run some code with the replaced stdout
    finally:
        sys.stdout.flush()
        sys.stdout = old_target  # restore to the previous value

'''
real_raw_input = vars(__builtins__).get('raw_input',input)
'''
try:
    import __builtin__

    input = getattr(__builtin__, 'raw_input')
except (ImportError, AttributeError):
    pass

from distutils.util import strtobool


def user_yes_no_query(question):
    sys.stdout.write('%s [y/n]\n' % question)
    while True:
        try:
            return strtobool(input().lower())
        except ValueError:
            sys.stdout.write('Please respond with \'y\' or \'n\'.\n')


# if user_yes_no_query('want to exit?') == 1: sys.exit()

abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
fname = os.path.basename(abspath)
os.chdir(dname)

# PrintToOutputFile = True

sqr05 = 0.5 ** 0.5

# ---- Initial definition of variables; the actual values will be read in with exec(open('./optic_input.py').read()) below
# Do you want to calculate the errors? If not, just the GHK-parameters are determined.
ScriptVersion = "0.9.8d"
Error_Calc = True
LID = "internal"
EID = "internal"
# --- IL Laser IL and +-Uncertainty
DOLP, dDOLP, nDOLP = 0.995, 0.005, 1  # degree of linear polarization; default 1
RotL, dRotL, nRotL = 0.0, 0.0, 1  # alpha; rotation of laser polarization in degrees; default 0
# IL = 1e5      #photons in the laser beam, including detection efficiency of the telescope, atmodspheric and r^2 attenuation
# --- ME Emitter and +-Uncertainty
DiE, dDiE, nDiE = 0., 0.00, 1  # Diattenuation
TiE = 1.  # Unpolarized transmittance
RetE, dRetE, nRetE = 0., 180.0, 0  # Retardance in degrees
RotE, dRotE, nRotE = 0., 0.0, 0  # beta: Rotation of optical element in degrees
# --- MO Receiver Optics including telescope
DiO, dDiO, nDiO = -0.055, 0.003, 1
TiO = 0.9
RetO, dRetO, nRetO = 0., 180.0, 2
RotO, dRotO, nRotO = 0., 0.1, 1  # gamma
# --- PBS MT transmitting path defined with (TS,TP);  and +-Uncertainty
TP, dTP, nTP = 0.98, 0.02, 1
TS, dTS, nTS = 0.001, 0.001, 1
TiT = 0.5 * (TP + TS)
DiT = (TP - TS) / (TP + TS)
# PolFilter
RetT, dRetT, nRetT = 0., 180., 0
ERaT, dERaT, nERaT = 0.001, 0.001, 1
RotaT, dRotaT, nRotaT = 0., 3., 1
DaT = (1 - ERaT) / (1 + ERaT)
TaT = 0.5 * (1 + ERaT)
# --- PBS MR reflecting path defined with (RS,RP);  and +-Uncertainty
RS_RP_depend_on_TS_TP = False
if (RS_RP_depend_on_TS_TP):
    RP, dRP, nRP = 1 - TP, 0.00, 0
    RS, dRS, nRS = 1 - TS, 0.00, 0
else:
    RP, dRP, nRP = 0.05, 0.01, 1
    RS, dRS, nRS = 0.98, 0.01, 1
TiR = 0.5 * (RP + RS)
DiR = (RP - RS) / (RP + RS)
# PolFilter
RetR, dRetR, nRetR = 0., 180., 0
ERaR, dERaR, nERaR = 0.001, 0.001, 1
RotaR, dRotaR, nRotaR = 90., 3., 1
DaR = (1 - ERaR) / (1 + ERaR)
TaR = 0.5 * (1 + ERaR)

# +++ Orientation of the PBS with respect to the reference plane (see Polarisation-orientation.png and Polarisation-orientation-2.png in /system_settings)
#    Y = +1: polarisation in reference plane is finally transmitted, 
#    Y = -1: polarisation in reference plane is finally reflected.
Y = 1.

# Calibrator =  type defined by matrix values
LocC = 4  # location of calibrator: behind laser = 1; behind emitter = 2; before receiver = 3; before PBS = 4

# --- Additional attenuation (transmission of the ND-filter) during the calibration
TCalT, dTCalT, nTCalT  = 1, 0, 0        # transmitting path; error calc not working yet
TCalR, dTCalR, nTCalR = 1, 0, 0         # reflecting path; error calc not working yet

# *** signal noise error calculation
#   --- number of photon counts in the signal summed up in the calibration range during the calibration measurements
NCalT = 1e6     # default 1e6, assumed the same in +45° and -45° signals
NCalR = 1e6     # default 1e6, assumed the same in +45° and -45° signals
NILfac = 200    # duration of standard (0°) measurement relative to calibration measurements
nNCal = 0           # error nNCal: one-sigma in steps to left and right for calibration signals
nNI   = 0           # error nNI: one-sigma in steps to left and right for 0° signals
IoutTp0, IoutTp, dIoutTp0 = 0.5, 0.5, 0
IoutTm0, IoutTm, dIoutTm0 = 0.5, 0.5, 0
IoutRp0, IoutRp, dIoutRp0 = 0.5, 0.5, 0
IoutRm0, IoutRm, dIoutRm0 = 0.5, 0.5, 0
It0, It, dIt0 = 1 , 1, 0
Ir0, Ir, dTr0 = 1 , 1, 0
CalcFrom0deg = True

TypeC = 3  # linear polarizer calibrator
# example with extinction ratio 0.001
DiC, dDiC, nDiC = 1.0, 0., 0  # ideal 1.0
TiC = 0.5  # ideal 0.5
RetC, dRetC, nRetC = 0., 0., 0
RotC, dRotC, nRotC = 0.0, 0.1, 0  # constant calibrator offset epsilon
RotationErrorEpsilonForNormalMeasurements = False  # is in general False for TypeC == 3 calibrator

# Rotation error without calibrator: if False, then epsilon = 0 for normal measurements
RotationErrorEpsilonForNormalMeasurements = True
# BSR backscatter ratio
# BSR, dBSR, nBSR = 10, 0.05, 1
BSR = np.zeros(5)
BSR = [1.1, 2, 5, 10, 50]
# theoretical molecular LDR  LDRm
LDRm, dLDRm, nLDRm = 0.004, 0.001, 1
# LDRCal assumed atmospheric linear depolarization ratio during the calibration measurements (first guess)
LDRCal0, dLDRCal, nLDRCal = 0.25, 0.04, 1
LDRCal = LDRCal0
# measured LDRm will be corrected with calculated parameters
LDRmeas = 0.015
# LDRtrue for simulation of measurement => LDRsim
LDRtrue = 0.5
LDRtrue2 = 0.004
LDRunCorr = 1
# Initialize other values to 0
ER, nER, dER = 0.001, 0, 0.001
K = 0.
Km = 0.
Kp = 0.
LDRcorr = 0.
Eta = 0.
Ir = 0.
It = 0.
h = 1.

Loc = ['', 'behind laser', 'behind emitter', 'before receiver', 'before PBS']
Type = ['', 'mechanical rotator', 'hwp rotator', 'linear polarizer', 'qwp rotator', 'circular polarizer',
        'real HWP +-22.5°']
dY = ['reflected channel', '', 'transmitted channel']
bPlotEtax = False

#  end of initial definition of variables
# *******************************************************************************************************************************

# --- Read actual lidar system parameters from optic_input.py  (must be in the programs sub-directory 'system_settings')
#InputFile = 'optic_input_example_lidar_2.py'
#InputFile = 'optic_input_example_lidar_3.py'
#InputFile = 'optic_input_example_lidar_4.py'
#InputFile = 'optic_input_example_lidar_5.py'
InputFile = 'optic_input_example_lidar.py'

'''
print("From ", dname)
print("Running ", fname)
print("Reading input file ", InputFile, " for")
'''
input_path = os.path.join('.', 'system_settings', InputFile)
# this works with Python 2 and 3!
exec (open(input_path).read(), globals())
#  end of read actual system parameters


# --- Manual Parameter Change ---
#  (use for quick parameter changes without changing the input file )
# DiO = 0.
# LDRtrue = 0.45
# LDRtrue2 = 0.004
# Y = -1
# LocC = 4 #location of calibrator: 1 = behind laser; 2 = behind emitter; 3 = before receiver; 4 = before PBS
##TypeC = 6  Don't change the TypeC here
# RotationErrorEpsilonForNormalMeasurements = True
# LDRCal = 0.25
## --- Errors
DOLP0, dDOLP, nDOLP = DOLP, dDOLP, nDOLP
RotL0, dRotL, nRotL = RotL, dRotL, nRotL

DiE0, dDiE, nDiE = DiE, dDiE, nDiE
RetE0, dRetE, nRetE = RetE, dRetE, nRetE
RotE0, dRotE, nRotE = RotE, dRotE, nRotE

DiO0, dDiO, nDiO = DiO, dDiO, nDiO
RetO0, dRetO, nRetO = RetO, dRetO, nRetO
RotO0, dRotO, nRotO = RotO, dRotO, nRotO

DiC0, dDiC, nDiC = DiC, dDiC, nDiC
RetC0, dRetC, nRetC = RetC, dRetC, nRetC
RotC0, dRotC, nRotC = RotC, dRotC, nRotC

TP0, dTP, nTP = TP, dTP, nTP
TS0, dTS, nTS = TS, dTS, nTS
RetT0, dRetT, nRetT = RetT, dRetT, nRetT

ERaT0, dERaT, nERaT = ERaT, dERaT, nERaT
RotaT0, dRotaT, nRotaT = RotaT, dRotaT, nRotaT

RP0, dRP, nRP = RP, dRP, nRP
RS0, dRS, nRS = RS, dRS, nRS
RetR0, dRetR, nRetR = RetR, dRetR, nRetR

ERaR0, dERaR, nERaR = ERaR, dERaR, nERaR
RotaR0, dRotaR, nRotaR = RotaR, dRotaR, nRotaR

LDRCal0, dLDRCal, nLDRCal = LDRCal, dLDRCal, nLDRCal

# BSR0, dBSR, nBSR = BSR, dBSR, nBSR
LDRm0, dLDRm, nLDRm = LDRm, dLDRm, nLDRm    
# ---------- End of manual parameter change

RotL, RotE, RetE, DiE, RotO, RetO, DiO, RotC, RetC, DiC = RotL0, RotE0, RetE0, DiE0, RotO0, RetO0, DiO0, RotC0, RetC0, DiC0
TP, TS, RP, RS, ERaT, RotaT, RetT, ERaR, RotaR, RetR = TP0, TS0, RP0, RS0, ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0
LDRCal = LDRCal0
DTa0, TTa0, DRa0, TRa0, LDRsimx, LDRCorr = 0, 0, 0, 0, 0, 0
TCalT0, TCalR0  = TCalT, TCalR

TiT = 0.5 * (TP + TS)
DiT = (TP - TS) / (TP + TS)
ZiT = (1. - DiT ** 2) ** 0.5
TiR = 0.5 * (RP + RS)
DiR = (RP - RS) / (RP + RS)
ZiR = (1. - DiR ** 2) ** 0.5

C2aT = np.cos(np.deg2rad(2 * RotaT))
C2aR = np.cos(np.deg2rad(2 * RotaR))
ATPT = (1 + C2aT * DaT * DiT)
ARPT = (1 + C2aR * DaR * DiR)
TTa = TiT * TaT * ATPT # unpolarized transmission   
TRa = TiR * TaR * ARPT # unpolarized transmission   
Eta0 = TRa / TTa                      
# --- this subroutine is for the calculation of the PLDR from LDR, BSR, and LDRm -----------------------------------------------------
def CalcPLDR(LDR, BSR, LDRm):
    PLDR = (BSR * (1. + LDRm) * LDR - LDRm * (1. + LDR)) / (BSR * (1. + LDRm) - (1. + LDR))
    return (PLDR)
# --- this subroutine is for the calculation with certain fixed parameters -----------------------------------------------------
def Calc(TCalT, TCalR, NCalT, NCalR, DOLP, RotL, RotE, RetE, DiE, RotO, RetO, DiO,
         RotC, RetC, DiC, TP, TS, RP, RS,
         ERaT, RotaT, RetT, ERaR, RotaR, RetR, LDRCal):
    # ---- Do the calculations of bra-ket vectors
    h = -1. if TypeC == 2 else 1
    # from input file:  assumed LDRCal for calibration measurements
    aCal = (1. - LDRCal) / (1 + LDRCal)
    # from input file: measured LDRm and true LDRtrue, LDRtrue2  =>
    # ameas = (1.-LDRmeas)/(1+LDRmeas)
    atrue = (1. - LDRtrue) / (1 + LDRtrue)
    # atrue2 = (1.-LDRtrue2)/(1+LDRtrue2)

    # angles of emitter and laser and calibrator and receiver optics
    # RotL = alpha, RotE = beta, RotO = gamma, RotC = epsilon
    S2a = np.sin(2 * np.deg2rad(RotL))
    C2a = np.cos(2 * np.deg2rad(RotL))
    S2b = np.sin(2 * np.deg2rad(RotE))
    C2b = np.cos(2 * np.deg2rad(RotE))
    S2ab = np.sin(np.deg2rad(2 * RotL - 2 * RotE))
    C2ab = np.cos(np.deg2rad(2 * RotL - 2 * RotE))
    S2g = np.sin(np.deg2rad(2 * RotO))
    C2g = np.cos(np.deg2rad(2 * RotO))

    # Laser with Degree of linear polarization DOLP
    IinL = 1.
    QinL = DOLP
    UinL = 0.
    VinL = (1. - DOLP ** 2) ** 0.5

    # Stokes Input Vector rotation Eq. E.4
    A = C2a * QinL - S2a * UinL
    B = S2a * QinL + C2a * UinL
    # Stokes Input Vector rotation Eq. E.9
    C = C2ab * QinL - S2ab * UinL
    D = S2ab * QinL + C2ab * UinL

    # emitter optics
    CosE = np.cos(np.deg2rad(RetE))
    SinE = np.sin(np.deg2rad(RetE))
    ZiE = (1. - DiE ** 2) ** 0.5
    WiE = (1. - ZiE * CosE)

    # Stokes Input Vector after emitter optics equivalent to Eq. E.9 with already rotated input vector from Eq. E.4
    # b = beta
    IinE = (IinL + DiE * C)
    QinE = (C2b * DiE * IinL + A + S2b * (WiE * D - ZiE * SinE * VinL))
    UinE = (S2b * DiE * IinL + B - C2b * (WiE * D - ZiE * SinE * VinL))
    VinE = (-ZiE * SinE * D + ZiE * CosE * VinL)

    # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
    IinF = IinE
    QinF = aCal * QinE
    UinF = -aCal * UinE
    VinF = (1. - 2. * aCal) * VinE

    # receiver optics
    CosO = np.cos(np.deg2rad(RetO))
    SinO = np.sin(np.deg2rad(RetO))
    ZiO = (1. - DiO ** 2) ** 0.5
    WiO = (1. - ZiO * CosO)

    # calibrator
    CosC = np.cos(np.deg2rad(RetC))
    SinC = np.sin(np.deg2rad(RetC))
    ZiC = (1. - DiC ** 2) ** 0.5
    WiC = (1. - ZiC * CosC)

    # Stokes Input Vector before the polarising beam splitter Eq. E.31
    A = C2g * QinE - S2g * UinE
    B = S2g * QinE + C2g * UinE

    IinP = (IinE + DiO * aCal * A)
    QinP = (C2g * DiO * IinE + aCal * QinE - S2g * (WiO * aCal * B + ZiO * SinO * (1 - 2 * aCal) * VinE))
    UinP = (S2g * DiO * IinE - aCal * UinE + C2g * (WiO * aCal * B + ZiO * SinO * (1 - 2 * aCal) * VinE))
    VinP = (ZiO * SinO * aCal * B + ZiO * CosO * (1 - 2 * aCal) * VinE)

    # -------------------------
    # F11 assuemd to be = 1  => measured: F11m = IinP / IinE with atrue
    # F11sim = TiO*(IinE + DiO*atrue*A)/IinE
    # -------------------------

    # analyser
    if (RS_RP_depend_on_TS_TP):
        RS = 1 - TS
        RP = 1 - TP

    TiT = 0.5 * (TP + TS)
    DiT = (TP - TS) / (TP + TS)
    ZiT = (1. - DiT ** 2) ** 0.5
    TiR = 0.5 * (RP + RS)
    DiR = (RP - RS) / (RP + RS)
    ZiR = (1. - DiR ** 2) ** 0.5
    CosT = np.cos(np.deg2rad(RetT))
    SinT = np.sin(np.deg2rad(RetT))
    CosR = np.cos(np.deg2rad(RetR))
    SinR = np.sin(np.deg2rad(RetR))

    DaT = (1 - ERaT) / (1 + ERaT)
    DaR = (1 - ERaR) / (1 + ERaR)
    TaT = 0.5 * (1 + ERaT)
    TaR = 0.5 * (1 + ERaR)

    S2aT = np.sin(np.deg2rad(h * 2 * RotaT))
    C2aT = np.cos(np.deg2rad(2 * RotaT))
    S2aR = np.sin(np.deg2rad(h * 2 * RotaR))
    C2aR = np.cos(np.deg2rad(2 * RotaR))

    # Analyzer As before the PBS Eq. D.5; combined PBS and cleaning pol-filter
    ATPT = (1 + C2aT * DaT * DiT) # unpolarized transmission correction
    TTa = TiT * TaT * ATPT # unpolarized transmission   
    ATP1 = 1
    ATP2 = Y * (DiT + C2aT * DaT) / ATPT
    ATP3 = Y * S2aT * DaT * ZiT * CosT / ATPT
    ATP4 = S2aT * DaT * ZiT * SinT / ATPT
    ATP = np.array([ATP1, ATP2, ATP3, ATP4])
    DTa = ATP2 * Y  

    ARPT = (1 + C2aR * DaR * DiR) # unpolarized transmission correction
    TRa = TiR * TaR * ARPT # unpolarized transmission   
    ARP1 = 1
    ARP2 = Y * (DiR + C2aR * DaR) / ARPT
    ARP3 = Y * S2aR * DaR * ZiR * CosR / ARPT
    ARP4 = S2aR * DaR * ZiR * SinR / ARPT
    ARP = np.array([ARP1, ARP2, ARP3, ARP4])
    DRa = ARP2 * Y


    # ---- Calculate signals and correction parameters for diffeent locations and calibrators
    if LocC == 4:  # Calibrator before the PBS
        # print("Calibrator location not implemented yet")

        # S2ge = np.sin(np.deg2rad(2*RotO + h*2*RotC))
        # C2ge = np.cos(np.deg2rad(2*RotO + h*2*RotC))
        S2e = np.sin(np.deg2rad(h * 2 * RotC))
        C2e = np.cos(np.deg2rad(2 * RotC))
        # rotated AinP by epsilon Eq. C.3
        ATP2e = C2e * ATP2 + S2e * ATP3
        ATP3e = C2e * ATP3 - S2e * ATP2
        ARP2e = C2e * ARP2 + S2e * ARP3
        ARP3e = C2e * ARP3 - S2e * ARP2
        ATPe = np.array([ATP1, ATP2e, ATP3e, ATP4])
        ARPe = np.array([ARP1, ARP2e, ARP3e, ARP4])
        # Stokes Input Vector before the polarising beam splitter Eq. E.31
        A = C2g * QinE - S2g * UinE
        B = S2g * QinE + C2g * UinE
        # C = (WiO*aCal*B + ZiO*SinO*(1-2*aCal)*VinE)
        Co = ZiO * SinO * VinE
        Ca = (WiO * B - 2 * ZiO * SinO * VinE)
        # C = Co + aCal*Ca
        # IinP = (IinE + DiO*aCal*A)
        # QinP = (C2g*DiO*IinE + aCal*QinE - S2g*C)
        # UinP = (S2g*DiO*IinE - aCal*UinE + C2g*C)
        # VinP = (ZiO*SinO*aCal*B + ZiO*CosO*(1-2*aCal)*VinE)
        IinPo = IinE
        QinPo = (C2g * DiO * IinE - S2g * Co)
        UinPo = (S2g * DiO * IinE + C2g * Co)
        VinPo = ZiO * CosO * VinE

        IinPa = DiO * A
        QinPa = QinE - S2g * Ca
        UinPa = -UinE + C2g * Ca
        VinPa = ZiO * (SinO * B - 2 * CosO * VinE)

        IinP = IinPo + aCal * IinPa
        QinP = QinPo + aCal * QinPa
        UinP = UinPo + aCal * UinPa
        VinP = VinPo + aCal * VinPa
        # Stokes Input Vector before the polarising beam splitter rotated by epsilon Eq. C.3
        # QinPe = C2e*QinP + S2e*UinP
        # UinPe = C2e*UinP - S2e*QinP
        QinPoe = C2e * QinPo + S2e * UinPo
        UinPoe = C2e * UinPo - S2e * QinPo
        QinPae = C2e * QinPa + S2e * UinPa
        UinPae = C2e * UinPa - S2e * QinPa
        QinPe = C2e * QinP + S2e * UinP
        UinPe = C2e * UinP - S2e * QinP

        # Calibration signals and Calibration correction K from measurements with LDRCal / aCal
        if (TypeC == 2) or (TypeC == 1):  # rotator calibration Eq. C.4
            # parameters for calibration with aCal
            AT = ATP1 * IinP + h * ATP4 * VinP
            BT = ATP3e * QinP - h * ATP2e * UinP
            AR = ARP1 * IinP + h * ARP4 * VinP
            BR = ARP3e * QinP - h * ARP2e * UinP
            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                GT = np.dot(ATP, IS1)
                GR = np.dot(ARP, IS1)
                HT = np.dot(ATP, IS2)
                HR = np.dot(ARP, IS2)
            else:
                IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                GT = np.dot(ATPe, IS1)
                GR = np.dot(ARPe, IS1)
                HT = np.dot(ATPe, IS2)
                HR = np.dot(ARPe, IS2)
        elif (TypeC == 3) or (TypeC == 4):  # linear polariser calibration Eq. C.5
            # parameters for calibration with aCal
            AT = ATP1 * IinP + ATP3e * UinPe + ZiC * CosC * (ATP2e * QinPe + ATP4 * VinP)
            BT = DiC * (ATP1 * UinPe + ATP3e * IinP) - ZiC * SinC * (ATP2e * VinP - ATP4 * QinPe)
            AR = ARP1 * IinP + ARP3e * UinPe + ZiC * CosC * (ARP2e * QinPe + ARP4 * VinP)
            BR = DiC * (ARP1 * UinPe + ARP3e * IinP) - ZiC * SinC * (ARP2e * VinP - ARP4 * QinPe)
            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                GT = np.dot(ATP, IS1)
                GR = np.dot(ARP, IS1)
                HT = np.dot(ATP, IS2)
                HR = np.dot(ARP, IS2)
            else:
                IS1e = np.array([IinPo + DiC * QinPoe, DiC * IinPo + QinPoe, ZiC * (CosC * UinPoe + SinC * VinPo),
                                 -ZiC * (SinC * UinPoe - CosC * VinPo)])
                IS2e = np.array([IinPa + DiC * QinPae, DiC * IinPa + QinPae, ZiC * (CosC * UinPae + SinC * VinPa),
                                 -ZiC * (SinC * UinPae - CosC * VinPa)])
                GT = np.dot(ATPe, IS1e)
                GR = np.dot(ARPe, IS1e)
                HT = np.dot(ATPe, IS2e)
                HR = np.dot(ARPe, IS2e)
        elif (TypeC == 6):  # diattenuator calibration +-22.5° rotated_diattenuator_X22x5deg.odt
            # parameters for calibration with aCal
            AT = ATP1 * IinP + sqr05 * DiC * (ATP1 * QinPe + ATP2e * IinP) + (1 - 0.5 * WiC) * (
            ATP2e * QinPe + ATP3e * UinPe) + ZiC * (sqr05 * SinC * (ATP3e * VinP - ATP4 * UinPe) + ATP4 * CosC * VinP)
            BT = sqr05 * DiC * (ATP1 * UinPe + ATP3e * IinP) + 0.5 * WiC * (
            ATP2e * UinPe + ATP3e * QinPe) - sqr05 * ZiC * SinC * (ATP2e * VinP - ATP4 * QinPe)
            AR = ARP1 * IinP + sqr05 * DiC * (ARP1 * QinPe + ARP2e * IinP) + (1 - 0.5 * WiC) * (
            ARP2e * QinPe + ARP3e * UinPe) + ZiC * (sqr05 * SinC * (ARP3e * VinP - ARP4 * UinPe) + ARP4 * CosC * VinP)
            BR = sqr05 * DiC * (ARP1 * UinPe + ARP3e * IinP) + 0.5 * WiC * (
            ARP2e * UinPe + ARP3e * QinPe) - sqr05 * ZiC * SinC * (ARP2e * VinP - ARP4 * QinPe)
            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                GT = np.dot(ATP, IS1)
                GR = np.dot(ARP, IS1)
                HT = np.dot(ATP, IS2)
                HR = np.dot(ARP, IS2)
            else:
                IS1e = np.array([IinPo + DiC * QinPoe, DiC * IinPo + QinPoe, ZiC * (CosC * UinPoe + SinC * VinPo),
                                 -ZiC * (SinC * UinPoe - CosC * VinPo)])
                IS2e = np.array([IinPa + DiC * QinPae, DiC * IinPa + QinPae, ZiC * (CosC * UinPae + SinC * VinPa),
                                 -ZiC * (SinC * UinPae - CosC * VinPa)])
                GT = np.dot(ATPe, IS1e)
                GR = np.dot(ARPe, IS1e)
                HT = np.dot(ATPe, IS2e)
                HR = np.dot(ARPe, IS2e)
        else:
            print("Calibrator not implemented yet")
            sys.exit()

    elif LocC == 3:  # C before receiver optics Eq.57

        # S2ge = np.sin(np.deg2rad(2*RotO - 2*RotC))
        # C2ge = np.cos(np.deg2rad(2*RotO - 2*RotC))
        S2e = np.sin(np.deg2rad(2 * RotC))
        C2e = np.cos(np.deg2rad(2 * RotC))

        # As with C before the receiver optics (rotated_diattenuator_X22x5deg.odt)
        AF1 = np.array([1, C2g * DiO, S2g * DiO, 0])
        AF2 = np.array([C2g * DiO, 1 - S2g ** 2 * WiO, S2g * C2g * WiO, -S2g * ZiO * SinO])
        AF3 = np.array([S2g * DiO, S2g * C2g * WiO, 1 - C2g ** 2 * WiO, C2g * ZiO * SinO])
        AF4 = np.array([0, S2g * SinO, -C2g * SinO, CosO])

        ATF = (ATP1 * AF1 + ATP2 * AF2 + ATP3 * AF3 + ATP4 * AF4)
        ARF = (ARP1 * AF1 + ARP2 * AF2 + ARP3 * AF3 + ARP4 * AF4)
        ATF2 = ATF[1]
        ATF3 = ATF[2]
        ARF2 = ARF[1]
        ARF3 = ARF[2]

        # rotated AinF by epsilon
        ATF1 = ATF[0]
        ATF4 = ATF[3]
        ATF2e = C2e * ATF[1] + S2e * ATF[2]
        ATF3e = C2e * ATF[2] - S2e * ATF[1]
        ARF1 = ARF[0]
        ARF4 = ARF[3]
        ARF2e = C2e * ARF[1] + S2e * ARF[2]
        ARF3e = C2e * ARF[2] - S2e * ARF[1]

        ATFe = np.array([ATF1, ATF2e, ATF3e, ATF4])
        ARFe = np.array([ARF1, ARF2e, ARF3e, ARF4])

        QinEe = C2e * QinE + S2e * UinE
        UinEe = C2e * UinE - S2e * QinE

        # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
        IinF = IinE
        QinF = aCal * QinE
        UinF = -aCal * UinE
        VinF = (1. - 2. * aCal) * VinE

        IinFo = IinE
        QinFo = 0.
        UinFo = 0.
        VinFo = VinE

        IinFa = 0.
        QinFa = QinE
        UinFa = -UinE
        VinFa = -2. * VinE

        # Stokes Input Vector before receiver optics rotated by epsilon Eq. C.3
        QinFe = C2e * QinF + S2e * UinF
        UinFe = C2e * UinF - S2e * QinF
        QinFoe = C2e * QinFo + S2e * UinFo
        UinFoe = C2e * UinFo - S2e * QinFo
        QinFae = C2e * QinFa + S2e * UinFa
        UinFae = C2e * UinFa - S2e * QinFa

        # Calibration signals and Calibration correction K from measurements with LDRCal / aCal
        if (TypeC == 2) or (TypeC == 1):  # rotator calibration Eq. C.4
            # parameters for calibration with aCal
            AT = ATF1 * IinF + ATF4 * h * VinF
            BT = ATF3e * QinF - ATF2e * h * UinF
            AR = ARF1 * IinF + ARF4 * h * VinF
            BR = ARF3e * QinF - ARF2e * h * UinF
            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):
                GT = ATF1 * IinE + ATF4 * VinE
                GR = ARF1 * IinE + ARF4 * VinE
                HT = ATF2 * QinE - ATF3 * UinE - ATF4 * 2 * VinE
                HR = ARF2 * QinE - ARF3 * UinE - ARF4 * 2 * VinE
            else:
                GT = ATF1 * IinE + ATF4 * h * VinE
                GR = ARF1 * IinE + ARF4 * h * VinE
                HT = ATF2e * QinE - ATF3e * h * UinE - ATF4 * h * 2 * VinE
                HR = ARF2e * QinE - ARF3e * h * UinE - ARF4 * h * 2 * VinE
        elif (TypeC == 3) or (TypeC == 4):  # linear polariser calibration Eq. C.5
            # p = +45°, m = -45°
            IF1e = np.array([IinF, ZiC * CosC * QinFe, UinFe, ZiC * CosC * VinF])
            IF2e = np.array([DiC * UinFe, -ZiC * SinC * VinF, DiC * IinF, ZiC * SinC * QinFe])
            AT = np.dot(ATFe, IF1e)
            AR = np.dot(ARFe, IF1e)
            BT = np.dot(ATFe, IF2e)
            BR = np.dot(ARFe, IF2e)

            # Correction parameters for normal measurements; they are independent of LDR  --- the same as for TypeC = 6
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                IS1 = np.array([IinE, 0, 0, VinE])
                IS2 = np.array([0, QinE, -UinE, -2 * VinE])
                GT = np.dot(ATF, IS1)
                GR = np.dot(ARF, IS1)
                HT = np.dot(ATF, IS2)
                HR = np.dot(ARF, IS2)
            else:
                IS1e = np.array([IinFo + DiC * QinFoe, DiC * IinFo + QinFoe, ZiC * (CosC * UinFoe + SinC * VinFo),
                                 -ZiC * (SinC * UinFoe - CosC * VinFo)])
                IS2e = np.array([IinFa + DiC * QinFae, DiC * IinFa + QinFae, ZiC * (CosC * UinFae + SinC * VinFa),
                                 -ZiC * (SinC * UinFae - CosC * VinFa)])
                GT = np.dot(ATFe, IS1e)
                GR = np.dot(ARFe, IS1e)
                HT = np.dot(ATFe, IS2e)
                HR = np.dot(ARFe, IS2e)

        elif (TypeC == 6):  # diattenuator calibration +-22.5° rotated_diattenuator_X22x5deg.odt
            # parameters for calibration with aCal
            IF1e = np.array([IinF + sqr05 * DiC * QinFe, sqr05 * DiC * IinF + (1 - 0.5 * WiC) * QinFe,
                             (1 - 0.5 * WiC) * UinFe + sqr05 * ZiC * SinC * VinF,
                             -sqr05 * ZiC * SinC * UinFe + ZiC * CosC * VinF])
            IF2e = np.array([sqr05 * DiC * UinFe, 0.5 * WiC * UinFe - sqr05 * ZiC * SinC * VinF,
                             sqr05 * DiC * IinF + 0.5 * WiC * QinFe, sqr05 * ZiC * SinC * QinFe])
            AT = np.dot(ATFe, IF1e)
            AR = np.dot(ARFe, IF1e)
            BT = np.dot(ATFe, IF2e)
            BR = np.dot(ARFe, IF2e)

            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                # IS1 = np.array([IinE,0,0,VinE])
                # IS2 = np.array([0,QinE,-UinE,-2*VinE])
                IS1 = np.array([IinFo, 0, 0, VinFo])
                IS2 = np.array([0, QinFa, UinFa, VinFa])
                GT = np.dot(ATF, IS1)
                GR = np.dot(ARF, IS1)
                HT = np.dot(ATF, IS2)
                HR = np.dot(ARF, IS2)
            else:
                IS1e = np.array([IinFo + DiC * QinFoe, DiC * IinFo + QinFoe, ZiC * (CosC * UinFoe + SinC * VinFo),
                                 -ZiC * (SinC * UinFoe - CosC * VinFo)])
                IS2e = np.array([IinFa + DiC * QinFae, DiC * IinFa + QinFae, ZiC * (CosC * UinFae + SinC * VinFa),
                                 -ZiC * (SinC * UinFae - CosC * VinFa)])
                # IS1e = np.array([IinFo,0,0,VinFo])
                # IS2e = np.array([0,QinFae,UinFae,VinFa])
                GT = np.dot(ATFe, IS1e)
                GR = np.dot(ARFe, IS1e)
                HT = np.dot(ATFe, IS2e)
                HR = np.dot(ARFe, IS2e)

        else:
            print('Calibrator not implemented yet')
            sys.exit()

    elif LocC == 2:  # C behind emitter optics Eq.57 -------------------------------------------------------
        # print("Calibrator location not implemented yet")
        S2e = np.sin(np.deg2rad(2 * RotC))
        C2e = np.cos(np.deg2rad(2 * RotC))

        # AS with C before the receiver optics (see document rotated_diattenuator_X22x5deg.odt)
        AF1 = np.array([1, C2g * DiO, S2g * DiO, 0])
        AF2 = np.array([C2g * DiO, 1 - S2g ** 2 * WiO, S2g * C2g * WiO, -S2g * ZiO * SinO])
        AF3 = np.array([S2g * DiO, S2g * C2g * WiO, 1 - C2g ** 2 * WiO, C2g * ZiO * SinO])
        AF4 = np.array([0, S2g * SinO, -C2g * SinO, CosO])

        ATF = (ATP1 * AF1 + ATP2 * AF2 + ATP3 * AF3 + ATP4 * AF4)
        ARF = (ARP1 * AF1 + ARP2 * AF2 + ARP3 * AF3 + ARP4 * AF4)
        ATF1 = ATF[0]
        ATF2 = ATF[1]
        ATF3 = ATF[2]
        ATF4 = ATF[3]
        ARF1 = ARF[0]
        ARF2 = ARF[1]
        ARF3 = ARF[2]
        ARF4 = ARF[3]

        # AS with C behind the emitter
        # terms without aCal
        ATE1o, ARE1o = ATF1, ARF1
        ATE2o, ARE2o = 0., 0.
        ATE3o, ARE3o = 0., 0.
        ATE4o, ARE4o = ATF4, ARF4
        # terms with aCal
        ATE1a, ARE1a = 0., 0.
        ATE2a, ARE2a = ATF2, ARF2
        ATE3a, ARE3a = -ATF3, -ARF3
        ATE4a, ARE4a = -2 * ATF4, -2 * ARF4
        # rotated AinEa by epsilon
        ATE2ae = C2e * ATF2 + S2e * ATF3
        ATE3ae = -S2e * ATF2 - C2e * ATF3
        ARE2ae = C2e * ARF2 + S2e * ARF3
        ARE3ae = -S2e * ARF2 - C2e * ARF3

        ATE1 = ATE1o
        ATE2e = aCal * ATE2ae
        ATE3e = aCal * ATE3ae
        ATE4 = (1 - 2 * aCal) * ATF4
        ARE1 = ARE1o
        ARE2e = aCal * ARE2ae
        ARE3e = aCal * ARE3ae
        ARE4 = (1 - 2 * aCal) * ARF4

        # rotated IinE
        QinEe = C2e * QinE + S2e * UinE
        UinEe = C2e * UinE - S2e * QinE

        # Calibration signals and Calibration correction K from measurements with LDRCal / aCal
        if (TypeC == 2) or (TypeC == 1):  # +++++++++ rotator calibration Eq. C.4
            AT = ATE1o * IinE + (ATE4o + aCal * ATE4a) * h * VinE
            BT = aCal * (ATE3ae * QinEe - ATE2ae * h * UinEe)
            AR = ARE1o * IinE + (ARE4o + aCal * ARE4a) * h * VinE
            BR = aCal * (ARE3ae * QinEe - ARE2ae * h * UinEe)

            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):
                # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
                GT = ATE1o * IinE + ATE4o * h * VinE
                GR = ARE1o * IinE + ARE4o * h * VinE
                HT = ATE2a * QinE + ATE3a * h * UinEe + ATE4a * h * VinE
                HR = ARE2a * QinE + ARE3a * h * UinEe + ARE4a * h * VinE
            else:
                GT = ATE1o * IinE + ATE4o * h * VinE
                GR = ARE1o * IinE + ARE4o * h * VinE
                HT = ATE2ae * QinE + ATE3ae * h * UinEe + ATE4a * h * VinE
                HR = ARE2ae * QinE + ARE3ae * h * UinEe + ARE4a * h * VinE

        elif (TypeC == 3) or (TypeC == 4):  # +++++++++ linear polariser calibration Eq. C.5
            # p = +45°, m = -45°
            AT = ATE1 * IinE + ZiC * CosC * (ATE2e * QinEe + ATE4 * VinE) + ATE3e * UinEe
            BT = DiC * (ATE1 * UinEe + ATE3e * IinE) + ZiC * SinC * (ATE4 * QinEe - ATE2e * VinE)
            AR = ARE1 * IinE + ZiC * CosC * (ARE2e * QinEe + ARE4 * VinE) + ARE3e * UinEe
            BR = DiC * (ARE1 * UinEe + ARE3e * IinE) + ZiC * SinC * (ARE4 * QinEe - ARE2e * VinE)

            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):
                # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
                GT = ATE1o * IinE + ATE4o * VinE
                GR = ARE1o * IinE + ARE4o * VinE
                HT = ATE2a * QinE + ATE3a * UinE + ATE4a * VinE
                HR = ARE2a * QinE + ARE3a * UinE + ARE4a * VinE
            else:
                D = IinE + DiC * QinEe
                A = DiC * IinE + QinEe
                B = ZiC * (CosC * UinEe + SinC * VinE)
                C = -ZiC * (SinC * UinEe - CosC * VinE)
                GT = ATE1o * D + ATE4o * C
                GR = ARE1o * D + ARE4o * C
                HT = ATE2a * A + ATE3a * B + ATE4a * C
                HR = ARE2a * A + ARE3a * B + ARE4a * C

        elif (TypeC == 6):  # real HWP calibration +-22.5° rotated_diattenuator_X22x5deg.odt
            # p = +22.5°, m = -22.5°
            IE1e = np.array([IinE + sqr05 * DiC * QinEe, sqr05 * DiC * IinE + (1 - 0.5 * WiC) * QinEe,
                             (1 - 0.5 * WiC) * UinEe + sqr05 * ZiC * SinC * VinE,
                             -sqr05 * ZiC * SinC * UinEe + ZiC * CosC * VinE])
            IE2e = np.array([sqr05 * DiC * UinEe, 0.5 * WiC * UinEe - sqr05 * ZiC * SinC * VinE,
                             sqr05 * DiC * IinE + 0.5 * WiC * QinEe, sqr05 * ZiC * SinC * QinEe])
            ATEe = np.array([ATE1, ATE2e, ATE3e, ATE4])
            AREe = np.array([ARE1, ARE2e, ARE3e, ARE4])
            AT = np.dot(ATEe, IE1e)
            AR = np.dot(AREe, IE1e)
            BT = np.dot(ATEe, IE2e)
            BR = np.dot(AREe, IE2e)

            # Correction parameters for normal measurements; they are independent of LDR
            if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                GT = ATE1o * IinE + ATE4o * VinE
                GR = ARE1o * IinE + ARE4o * VinE
                HT = ATE2a * QinE + ATE3a * UinE + ATE4a * VinE
                HR = ARE2a * QinE + ARE3a * UinE + ARE4a * VinE
            else:
                D = IinE + DiC * QinEe
                A = DiC * IinE + QinEe
                B = ZiC * (CosC * UinEe + SinC * VinE)
                C = -ZiC * (SinC * UinEe - CosC * VinE)
                GT = ATE1o * D + ATE4o * C
                GR = ARE1o * D + ARE4o * C
                HT = ATE2a * A + ATE3a * B + ATE4a * C
                HR = ARE2a * A + ARE3a * B + ARE4a * C

        else:
            print('Calibrator not implemented yet')
            sys.exit()

    else:
        print("Calibrator location not implemented yet")
        sys.exit()

    # Determination of the correction K of the calibration factor. 
    IoutTp = TTa * TiC * TiO * TiE * (AT + BT)
    IoutTm = TTa * TiC * TiO * TiE * (AT - BT)
    IoutRp = TRa * TiC * TiO * TiE * (AR + BR)
    IoutRm = TRa * TiC * TiO * TiE * (AR - BR)
    # --- Results and Corrections; electronic etaR and etaT are assumed to be 1
    Etapx = IoutRp / IoutTp
    Etamx = IoutRm / IoutTm
    Etax = (Etapx * Etamx) ** 0.5

    Eta = (TRa / TTa) # = TRa / TTa; Eta = Eta*/K  Eq. 84 => K = Eta* / Eta; equation corrected according to the papers supplement Eqs. (S.10.10.1) ff
    K = Etax / Eta

    #  For comparison with Volkers Libreoffice Müller Matrix spreadsheet
    # Eta_test_p = (IoutRp/IoutTp)
    # Eta_test_m = (IoutRm/IoutTm)
    # Eta_test = (Eta_test_p*Eta_test_m)**0.5

    # ----- random error calculation ----------
    # noise must be calculated with the photon counts of measured signals;
    # relative standard deviation of calibration signals with LDRcal; assumed to be statisitcally independent
    # normalised noise errors
    if (CalcFrom0deg):
        dIoutTp = (NCalT * IoutTp) ** -0.5
        dIoutTm = (NCalT * IoutTm) ** -0.5
        dIoutRp = (NCalR * IoutRp) ** -0.5
        dIoutRm = (NCalR * IoutRm) ** -0.5
    else:
        dIoutTp = (NCalT ** -0.5)
        dIoutTm = (NCalT ** -0.5)
        dIoutRp = (NCalR ** -0.5)
        dIoutRm = (NCalR ** -0.5)
    # Forward simulated 0°-signals with LDRCal with atrue; from input file

    It = TTa * TiO * TiE * (GT + atrue * HT)
    Ir = TRa * TiO * TiE * (GR + atrue * HR)
    # relative standard deviation of standard signals with LDRmeas; assumed to be statisitcally independent
    if (CalcFrom0deg):
        dIt = ((NCalT * It / IoutTp * NILfac / TCalT) ** -0.5)
        dIr = ((NCalR * Ir / IoutRp * NILfac / TCalR) ** -0.5)
    else:
        dIt = ((NCalT * 2 * NILfac / TCalT ) ** -0.5) * It
        dIr = ((NCalR * 2 * NILfac / TCalR) ** -0.5) * Ir

        # ----- Forward simulated LDRsim = 1/Eta*Ir/It  # simulated LDR* with Y from input file
    LDRsim = Ir / It  # simulated uncorrected LDR with Y from input file
    # Corrected LDRsimCorr from forward simulated LDRsim (atrue)
    # LDRsimCorr = (1./Eta*LDRsim*(GT+HT)-(GR+HR))/((GR-HR)-1./Eta*LDRsim*(GT-HT))
    '''
    if ((Y == -1.) and (abs(RotL0) < 45)) or ((Y == +1.) and (abs(RotL0) > 45)):
        LDRsimx = 1. / LDRsim / Etax
    else:
        LDRsimx = LDRsim / Etax
    '''
    LDRsimx = LDRsim

    # The following is correct without doubt
    # LDRCorr = (LDRsim/(Etax/K)*(GT+HT)-(GR+HR))/((GR-HR)-LDRsim/(Etax/K)*(GT-HT))

    # The following is a test whether the equations for calibration Etax and normal  signal (GHK, LDRsim) are consistent
    LDRCorr = (LDRsim / (Etax / K) * (GT + HT) - (GR + HR)) / ((GR - HR) - LDRsim / (Etax / K) * (GT - HT))
    # here we could also use Eta instead of Etax / K => how to test whether Etax is correct? => comparison with MüllerMatrix simulation!
    # Without any correction: only measured It, Ir, EtaX are used
    LDRunCorr = (LDRsim / Etax * (GT / abs(GT) + HT / abs(HT)) - (GR / abs(GR) + HR / abs(HR))) / ((GR / abs(GR) - HR / abs(HR)) - LDRsim / Etax * (GT / abs(GT) - HT / abs(HT)))

    #LDRCorr = LDRsimx  # for test only

    F11sim = 1 / (TiO * TiE) * ((HR * Eta * It - HT * Ir) / (HR * GT - HT * GR))  # IL = 1, Etat = Etar = 1  ;  AMT Eq.64; what is Etax/K? => see about 20 lines above: = Eta

    return (IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr,
            GT, HT, GR, HR, K, Eta, LDRsimx, LDRCorr, DTa, DRa, TTa, TRa, F11sim, LDRunCorr)



# *******************************************************************************************************************************

# --- CALC with assumed true parameters from the input file
IoutTp0, IoutTm0, IoutRp0, IoutRm0, It0, Ir0, dIoutTp0, dIoutTm0, dIoutRp0, dIoutRm0, dIt0, dIr0, \
GT0, HT0, GR0, HR0, K0, Eta0, LDRsimx, LDRCorr, DTa0, DRa0, TTa0, TRa0, F11sim0, LDRunCorr = \
Calc(TCalT, TCalR, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
     RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
     ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal0)
Etax0 = K0 * Eta0
# --- Print parameters to console and output file
with open('output_files\\' + LID + '-' + InputFile[0:-3] + '-GHK.dat', 'w') as f:
    with redirect_stdout(f):
        print("From folder", dname)
        print("Running prog", fname)
        print("Version", ScriptVersion)
        print("Reading input file ", InputFile)  # , "  for Lidar system :", EID, ", ", LID)
        print("for Lidar system: ", EID, ", ", LID)
        # --- Print iput information*********************************
        print(" --- Input parameters: value ±error / ±steps  ----------------------")
        print("{0:5}{1:5} {2:6.4f}±{3:7.4f}/{4:2d}; {5:8} {6:8.4f}±{7:7.4f}/{8:2d}".format(
            "Laser: ", "DOLP =", DOLP0, dDOLP, nDOLP," Rotation alpha =  ", RotL0, dRotL, nRotL))
        print("              Diatt.,             Tunpol,   Retard.,   Rotation (deg)")
        print("{0:12} {1:7.4f}±{2:7.4f}/{8:2d}, {3:7.4f}, {4:3.0f}±{5:3.0f}/{9:2d}, {6:7.4f}±{7:7.4f}/{10:2d}".format(
            "Emitter    ", DiE0, dDiE, TiE, RetE0, dRetE, RotE0, dRotE, nDiE, nRetE, nRotE))
        print("{0:12} {1:7.4f}±{2:7.4f}/{8:2d}, {3:7.4f}, {4:3.0f}±{5:3.0f}/{9:2d}, {6:7.4f}±{7:7.4f}/{10:2d}".format(
            "Receiver   ", DiO0, dDiO, TiO, RetO0, dRetO, RotO0, dRotO, nDiO, nRetO, nRotO))
        print("{0:12} {1:7.4f}±{2:7.4f}/{8:2d}, {3:7.4f}, {4:3.0f}±{5:3.0f}/{9:2d}, {6:7.4f}±{7:7.4f}/{10:2d}".format(
            "Calibrator ", DiC0, dDiC, TiC, RetC0, dRetC, RotC0, dRotC, nDiC, nRetC, nRotC))
        print("{0:12}".format(" --- Pol.-filter ---"))
        print("{0:12}{1:7.4f}±{2:7.4f}/{3:2d}, {4:7.4f}±{5:7.4f}/{6:2d}".format(
            "ERT, RotT       :", ERaT0, dERaT, nERaT, RotaT0, dRotaT, nRotaT))
        print("{0:12}{1:7.4f}±{2:7.4f}/{3:2d}, {4:7.4f}±{5:7.4f}/{6:2d}".format(
             "ERR, RotR       :", ERaR0, dERaR, nERaR, RotaR0, dRotaR, nRotaR))
        print("{0:12}".format(" --- PBS ---"))
        print("{0:12}{1:7.4f}±{2:7.4f}/{3:2d}, {4:7.4f}±{5:7.4f}/{6:2d}".format(
              "TP,TS           :", TP0, dTP, nTP, TS0, dTS, nTS))
        print("{0:12}{1:7.4f}±{2:7.4f}/{3:2d}, {4:7.4f}±{5:7.4f}/{6:2d}".format(
              "RP,RS           :", RP0, dRP, nRP, RS0, dRS, nRS))
        print("{0:12}{1:7.4f},{2:7.4f}, {3:7.4f},{4:7.4f}, {5:1.0f}".format(
              "DT,TT,DR,TR,Y   :", DiT, TiT, DiR, TiR, Y))
        print("{0:12}".format(" --- Combined PBS + Pol.-filter ---"))
        print("{0:12}{1:7.4f},{2:7.4f}, {3:7.4f},{4:7.4f}".format(
              "DT,TT,DR,TR     :", DTa0, TTa0, DRa0, TRa0))
        print("{0:26}: {1:6.3f}± {2:5.3f}/{3:2d}".format(
              "LDRCal during calibration in calibration range", LDRCal0, dLDRCal, nLDRCal))
        print("{0:12}".format(" --- Additional ND filter attenuation (transmission) during the calibration ---"))
        print("{0:12}{1:7.4f}±{2:7.4f}/{3:2d}, {4:7.4f}±{5:7.4f}/{6:2d}".format(
              "TCalT,TCalR      :", TCalT0, dTCalT, nTCalT, TCalR0, dTCalR, nTCalR))
        print()
        print("Rotation Error Epsilon For Normal Measurements = ", RotationErrorEpsilonForNormalMeasurements)
        print(Type[TypeC], Loc[LocC])
        print("Parallel signal detected in", dY[int(Y + 1)])
        print("RS_RP_depend_on_TS_TP = ", RS_RP_depend_on_TS_TP)
        #  end of print actual system parameters
        # ******************************************************************************

        # print()
        # print(" --- LDRCal during calibration | simulated and corrected LDRs -------------")
        # print("{0:8} |{1:8}->{2:8},{3:9}->{4:9} |{5:8}->{6:8}".format(" LDRCal"," LDRtrue", " LDRsim"," LDRtrue2", " LDRsim2", " LDRmeas", " LDRcorr"))
        # print("{0:8.5f} |{1:8.5f}->{2:8.5f},{3:9.5f}->{4:9.5f} |{5:8.5f}->{6:8.5f}".format(LDRCal, LDRtrue, LDRsim, LDRtrue2, LDRsim2, LDRmeas, LDRCorr))
        # print("{0:8}       |{1:8}->{2:8}->{3:8}".format(" LDRCal"," LDRtrue", " LDRsimx", " LDRcorr"))
        # print("{0:6.3f}±{1:5.3f}/{2:2d}|{3:8.5f}->{4:8.5f}->{5:8.5f}".format(LDRCal0, dLDRCal, nLDRCal, LDRtrue, LDRsimx, LDRCorr))
        # print("{0:8}       |{1:8}->{2:8}->{3:8}".format(" LDRCal"," LDRtrue", " LDRsimx", " LDRcorr"))
        # print(" --- LDRCal during calibration")

        # print("{0:8}={1:8.5f};{2:8}={3:8.5f}".format(" IinP",IinP," F11sim",F11sim))
        print()

        K0List = np.zeros(6)
        LDRsimxList = np.zeros(6)
        LDRCalList = 0.004, 0.02, 0.1, 0.2, 0.3, 0.45
        # The loop over LDRCalList is ony for checking whether and how much the LDR depends on the LDRCal during calibration and whether the corrections work.
        # Still with assumed true parameters in input file

        facIt = NCalT / TCalT0 * NILfac
        facIr = NCalR / TCalR0 * NILfac
        print("IoutTp, IoutTm, IoutRp, IoutRm, It    , Ir    , dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr")

        for i, LDRCal in enumerate(LDRCalList):
            IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr, \
            GT0, HT0, GR0, HR0, K0, Eta0, LDRsimx, LDRCorr, DTa0, DRa0, TTa0, TRa0, F11sim0, LDRunCorr = \
            Calc(TCalT0, TCalR0, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
                 RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
                 ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal)
            K0List[i] = K0
            LDRsimxList[i] = LDRsimx

            # check error signals
            # print( "{:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}"
            #    .format(IoutTp * NCalT, IoutTm * NCalT, IoutRp * NCalR, IoutRm * NCalR, It * facIt, Ir * facIr, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr))
            #print( "{:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}".format(IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr))
            # end check error signals
        print('===========================================================================================================')
        print("{0:8},{1:8},{2:8},{3:8},{4:9},{5:8},{6:9},{7:9},{8:9},{9:9}".format(
            " GR", " GT", " HR", " HT", "  K(0.004)", " K(0.02)", "  K(0.1)", "  K(0.2)", "  K(0.3)", "  K(0.45)"))
        print("{0:8.5f},{1:8.5f},{2:8.5f},{3:8.5f},{4:9.5f},{5:9.5f},{6:9.5f},{7:9.5f},{8:9.5f},{9:9.5f}".format(
            GR0, GT0, HR0, HT0, K0List[0], K0List[1], K0List[2], K0List[3], K0List[4], K0List[5]))
        print('===========================================================================================================')
        print()
        print("Errors from neglecting GHK corrections and/or calibration:")
        print("{0:>10},{1:>10},{2:>10},{3:>10},{4:>10},{5:>10}".format(
            "LDRtrue", "LDRunCorr", "1/LDRunCorr", "LDRsimx", "1/LDRsimx", "LDRCorr"))

        #LDRtrueList = 0.004, 0.02, 0.2, 0.45
        aF11sim0 = np.zeros(5)
        LDRrange = np.zeros(5)
        LDRrange = [0.004, 0.02, 0.1, 0.3, 0.45]  # list

        # The loop over LDRtrueList is only for checking how much the uncorrected LDRsimx deviates from LDRtrue ... and whether the corrections work.
        # LDRsimx = LDRsim = Ir / It    or      1/LDRsim
        # Still with assumed true parameters in input file
        for i, LDRtrue in enumerate(LDRrange):
        #for LDRtrue in LDRrange:
            IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr, \
            GT0, HT0, GR0, HR0, K0, Eta0, LDRsimx, LDRCorr, DTa0, DRa0, TTa0, TRa0, F11sim0, LDRunCorr = \
            Calc(TCalT0, TCalR0, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
                 RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
                 ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal0)
            print("{0:10.5f},{1:10.5f},{2:10.5f},{3:10.5f},{4:10.5f},{5:10.5f}".format(LDRtrue, LDRunCorr, 1/LDRunCorr, LDRsimx, 1/LDRsimx, LDRCorr))
            aF11sim0[i] = F11sim0
            # the assumed true aF11sim0 results will be used below to calc the deviation from the real signals
        print("LDRsimx = LDR of the nominal system directly from measured signals without  calibration and GHK-corrections")
        print("LDRunCorr = LDR of the nominal system directly from measured signals with calibration but without  GHK-corrections; electronic amplifications = 1 assumed")
        print("LDRCorr = LDR calibrated and GHK-corrected")
        print()
        print("Errors from signal noise:")
        print("Signal counts: NCalT, NCalR, NILfac, nNCal, nNI = {0:10.0f},{1:10.0f},{2:3.0f},{3:2.0f},{4:2.0f}".format(
            NCalT, NCalR, NILfac, nNCal, nNI))

        '''# das muß wieder weg
        print("IoutTp, IoutTm, IoutRp, IoutRm, It    , Ir    , dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr")
        LDRCal = 0.01
        for i, LDRtrue in enumerate(LDRrange):
            IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr, \
            GT0, HT0, GR0, HR0, K0, Eta0, LDRsimx, LDRCorr, DTa0, DRa0, TTa0, TRa0, F11sim0, LDRunCorr = \
            Calc(TCalT0, TCalR0, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
                 RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
                 ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal0)
            print( "{:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}, {:0.4f}".format(
                IoutTp * NCalT, IoutTm * NCalT, IoutRp * NCalR, IoutRm * NCalR, It * facIt, Ir * facIr,
                dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr))
            aF11sim0[i] = F11sim0
            # the assumed true aF11sim0 results will be used below to calc the deviation from the real signals
        # bis hierher weg
        '''

file = open('output_files\\' + LID + '-' + InputFile[0:-3] + '-GHK.dat', 'r')
print(file.read())
file.close()

'''
if(PrintToOutputFile):
    f = open('output_ver7.dat', 'w')
    old_target = sys.stdout
    sys.stdout = f

    print("something")

if(PrintToOutputFile):
    sys.stdout.flush()
    f.close
    sys.stdout = old_target
'''
if (Error_Calc):
    # --- CALC again assumed truth with LDRCal0 and with assumed true parameters in input file to reset all 0-values
    IoutTp0, IoutTm0, IoutRp0, IoutRm0, It0, Ir0, dIoutTp0, dIoutTm0, dIoutRp0, dIoutRm0, dIt0, dIr0, \
    GT0, HT0, GR0, HR0, K0, Eta0, LDRsimx, LDRCorr, DTa0, DRa0, TTa0, TRa0, F11sim0, LDRunCorr = \
    Calc(TCalT0, TCalR0, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
         RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
         ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal0)
    Etax0 = K0 * Eta0
    # --- Start Error calculation with variable parameters ------------------------------------------------------------------
    # error nNCal: one-sigma in steps to left and right for calibration signals
    # error nNI: one-sigma in steps to left and right for 0° signals

    iN = -1
    N = ((nTCalT * 2 + 1) * (nTCalR * 2 + 1) *
         (nNCal * 2 + 1) ** 4 * (nNI * 2 + 1) ** 2 *
         (nDOLP * 2 + 1) * (nRotL * 2 + 1) *
         (nRotE * 2 + 1) * (nRetE * 2 + 1) * (nDiE * 2 + 1) *
         (nRotO * 2 + 1) * (nRetO * 2 + 1) * (nDiO * 2 + 1) *
         (nRotC * 2 + 1) * (nRetC * 2 + 1) * (nDiC * 2 + 1) *
         (nTP * 2 + 1) * (nTS * 2 + 1) * (nRP * 2 + 1) * (nRS * 2 + 1) * (nERaT * 2 + 1) * (nERaR * 2 + 1) *
         (nRotaT * 2 + 1) * (nRotaR * 2 + 1) * (nRetT * 2 + 1) * (nRetR * 2 + 1) * (nLDRCal * 2 + 1))
    print("number of system variations N = ", N, " ", end="")

    if N > 1e6:
        if user_yes_no_query('Warning: processing ' + str(
            N) + ' samples will take very long. Do you want to proceed?') == 0: sys.exit()
    if N > 5e6:
        if user_yes_no_query('Warning: the memory required for ' + str(N) + ' samples might be ' + '{0:5.1f}'.format(
                    N / 4e6) + ' GB. Do you anyway want to proceed?') == 0: sys.exit()

    # if user_yes_no_query('Warning: processing' + str(N) + ' samples will take very long. Do you want to proceed?') == 0: sys.exit()

    # --- Arrays for plotting ------
    LDRmin = np.zeros(5)
    LDRmax = np.zeros(5)
    F11min = np.zeros(5)
    F11max = np.zeros(5)
    Etaxmin = np.zeros(5)
    Etaxmax = np.zeros(5)

    # LDRrange = np.zeros(5)
    # LDRrange = 0.004, 0.02, 0.1, 0.3, 0.45
    # aLDRsimx = np.zeros(N)
    # aLDRsimx2 = np.zeros(N)
    # aLDRcorr = np.zeros(N)
    # aLDRcorr2 = np.zeros(N)
    aDOLP = np.zeros(N)
    aERaT = np.zeros(N)
    aERaR = np.zeros(N)
    aRotaT = np.zeros(N)
    aRotaR = np.zeros(N)
    aRetT = np.zeros(N)
    aRetR = np.zeros(N)
    aTP = np.zeros(N)
    aTS = np.zeros(N)
    aRP = np.zeros(N)
    aRS = np.zeros(N)
    aDiE = np.zeros(N)
    aDiO = np.zeros(N)
    aDiC = np.zeros(N)
    aRotC = np.zeros(N)
    aRetC = np.zeros(N)
    aRotL = np.zeros(N)
    aRetE = np.zeros(N)
    aRotE = np.zeros(N)
    aRetO = np.zeros(N)
    aRotO = np.zeros(N)
    aLDRCal = np.zeros(N)
    aNCalTp = np.zeros(N)
    aNCalTm = np.zeros(N)
    aNCalRp = np.zeros(N)
    aNCalRm = np.zeros(N)
    aNIt = np.zeros(N)
    aNIr = np.zeros(N)
    aTCalT = np.zeros(N)
    aTCalR = np.zeros(N)

    # each np.zeros((LDRrange, N)) array has the same N-dependency
    aLDRcorr = np.zeros((5, N))
    aF11corr = np.zeros((5, N))
    aPLDR = np.zeros((5, N))
    aEtax = np.zeros((5, N))

    # np.zeros((GHKs, N))
    aGHK = np.zeros((5, N))

    atime = clock()
    dtime = clock()

    # --- Calc Error signals
    # ---- Do the calculations of bra-ket vectors
    h = -1. if TypeC == 2 else 1

    '''
    # from input file: measured LDRm and true LDRtrue, LDRtrue2  =>
    ameas = (1. - LDRmeas) / (1 + LDRmeas)
    atrue = (1. - LDRtrue) / (1 + LDRtrue)
    atrue2 = (1. - LDRtrue2) / (1 + LDRtrue2)
    '''

    for iLDRCal in range(-nLDRCal, nLDRCal + 1):
        # from input file:  LDRCal for calibration measurements
        LDRCal = LDRCal0
        if nLDRCal > 0:
            LDRCal = LDRCal0 + iLDRCal * dLDRCal / nLDRCal
            # provides the intensities of the calibration measurements at various LDRCal for signal noise errors
            # IoutTp, IoutTm, IoutRp, IoutRm, dIoutTp, dIoutTm, dIoutRp, dIoutRm
            '''
            IoutTp, IoutTm, IoutRp, IoutRm, It, Ir, dIoutTp, dIoutTm, dIoutRp, dIoutRm, dIt, dIr, \
            GT, HT, GR, HR, K, Eta, LDRsimx, LDRCorr, DTa, DRa, TTa, TRa, F11sim, LDRunCorr = \
            Calc(TCalT, TCalR, NCalT, NCalR, DOLP0, RotL0, RotE0, RetE0, DiE0,
                 RotO0, RetO0, DiO0, RotC0, RetC0, DiC0, TP0, TS0, RP0, RS0,
                 ERaT0, RotaT0, RetT0, ERaR0, RotaR0, RetR0, LDRCal)
            '''
        aCal = (1. - LDRCal) / (1 + LDRCal)
        for iDOLP, iRotL, iRotE, iRetE, iDiE \
                in [(iDOLP, iRotL, iRotE, iRetE, iDiE)
                    for iDOLP in range(-nDOLP, nDOLP + 1)
                    for iRotL in range(-nRotL, nRotL + 1)
                    for iRotE in range(-nRotE, nRotE + 1)
                    for iRetE in range(-nRetE, nRetE + 1)
                    for iDiE in range(-nDiE, nDiE + 1)]:

            if nDOLP > 0: DOLP = DOLP0 + iDOLP * dDOLP / nDOLP
            if nRotL > 0: RotL = RotL0 + iRotL * dRotL / nRotL
            if nRotE > 0: RotE = RotE0 + iRotE * dRotE / nRotE
            if nRetE > 0: RetE = RetE0 + iRetE * dRetE / nRetE
            if nDiE > 0:  DiE = DiE0 + iDiE * dDiE / nDiE

            # angles of emitter and laser and calibrator and receiver optics
            # RotL = alpha, RotE = beta, RotO = gamma, RotC = epsilon
            S2a = np.sin(2 * np.deg2rad(RotL))
            C2a = np.cos(2 * np.deg2rad(RotL))
            S2b = np.sin(2 * np.deg2rad(RotE))
            C2b = np.cos(2 * np.deg2rad(RotE))
            S2ab = np.sin(np.deg2rad(2 * RotL - 2 * RotE))
            C2ab = np.cos(np.deg2rad(2 * RotL - 2 * RotE))

            # Laser with Degree of linear polarization DOLP
            IinL = 1.
            QinL = DOLP
            UinL = 0.
            VinL = (1. - DOLP ** 2) ** 0.5

            # Stokes Input Vector rotation Eq. E.4
            A = C2a * QinL - S2a * UinL
            B = S2a * QinL + C2a * UinL
            # Stokes Input Vector rotation Eq. E.9
            C = C2ab * QinL - S2ab * UinL
            D = S2ab * QinL + C2ab * UinL

            # emitter optics
            CosE = np.cos(np.deg2rad(RetE))
            SinE = np.sin(np.deg2rad(RetE))
            ZiE = (1. - DiE ** 2) ** 0.5
            WiE = (1. - ZiE * CosE)

            # Stokes Input Vector after emitter optics equivalent to Eq. E.9 with already rotated input vector from Eq. E.4
            # b = beta
            IinE = (IinL + DiE * C)
            QinE = (C2b * DiE * IinL + A + S2b * (WiE * D - ZiE * SinE * VinL))
            UinE = (S2b * DiE * IinL + B - C2b * (WiE * D - ZiE * SinE * VinL))
            VinE = (-ZiE * SinE * D + ZiE * CosE * VinL)

            # -------------------------
            # F11 assuemd to be = 1  => measured: F11m = IinP / IinE with atrue
            # F11sim = (IinE + DiO*atrue*(C2g*QinE - S2g*UinE))/IinE
            # -------------------------

            for iRotO, iRetO, iDiO, iRotC, iRetC, iDiC, iTP, iTS, iRP, iRS, iERaT, iRotaT, iRetT, iERaR, iRotaR, iRetR \
                    in [
                (iRotO, iRetO, iDiO, iRotC, iRetC, iDiC, iTP, iTS, iRP, iRS, iERaT, iRotaT, iRetT, iERaR, iRotaR, iRetR)
                for iRotO in range(-nRotO, nRotO + 1)
                for iRetO in range(-nRetO, nRetO + 1)
                for iDiO in range(-nDiO, nDiO + 1)
                for iRotC in range(-nRotC, nRotC + 1)
                for iRetC in range(-nRetC, nRetC + 1)
                for iDiC in range(-nDiC, nDiC + 1)
                for iTP in range(-nTP, nTP + 1)
                for iTS in range(-nTS, nTS + 1)
                for iRP in range(-nRP, nRP + 1)
                for iRS in range(-nRS, nRS + 1)
                for iERaT in range(-nERaT, nERaT + 1)
                for iRotaT in range(-nRotaT, nRotaT + 1)
                for iRetT in range(-nRetT, nRetT + 1)
                for iERaR in range(-nERaR, nERaR + 1)
                for iRotaR in range(-nRotaR, nRotaR + 1)
                for iRetR in range(-nRetR, nRetR + 1)]:

                if nRotO > 0: RotO = RotO0 + iRotO * dRotO / nRotO
                if nRetO > 0: RetO = RetO0 + iRetO * dRetO / nRetO
                if nDiO > 0:  DiO = DiO0 + iDiO * dDiO / nDiO
                if nRotC > 0: RotC = RotC0 + iRotC * dRotC / nRotC
                if nRetC > 0: RetC = RetC0 + iRetC * dRetC / nRetC
                if nDiC > 0:  DiC = DiC0 + iDiC * dDiC / nDiC
                if nTP > 0:   TP = TP0 + iTP * dTP / nTP
                if nTS > 0:   TS = TS0 + iTS * dTS / nTS
                if nRP > 0:   RP = RP0 + iRP * dRP / nRP
                if nRS > 0:   RS = RS0 + iRS * dRS / nRS
                if nERaT > 0: ERaT = ERaT0 + iERaT * dERaT / nERaT
                if nRotaT > 0: RotaT = RotaT0 + iRotaT * dRotaT / nRotaT
                if nRetT > 0: RetT = RetT0 + iRetT * dRetT / nRetT
                if nERaR > 0: ERaR = ERaR0 + iERaR * dERaR / nERaR
                if nRotaR > 0: RotaR = RotaR0 + iRotaR * dRotaR / nRotaR
                if nRetR > 0: RetR = RetR0 + iRetR * dRetR / nRetR

                # print("{0:5.2f}, {1:5.2f}, {2:5.2f}, {3:10d}".format(RotL, RotE, RotO, iN))

                # receiver optics
                CosO = np.cos(np.deg2rad(RetO))
                SinO = np.sin(np.deg2rad(RetO))
                ZiO = (1. - DiO ** 2) ** 0.5
                WiO = (1. - ZiO * CosO)
                S2g = np.sin(np.deg2rad(2 * RotO))
                C2g = np.cos(np.deg2rad(2 * RotO))
                # calibrator
                CosC = np.cos(np.deg2rad(RetC))
                SinC = np.sin(np.deg2rad(RetC))
                ZiC = (1. - DiC ** 2) ** 0.5
                WiC = (1. - ZiC * CosC)

                # analyser
                # For POLLY_XTs
                if (RS_RP_depend_on_TS_TP):
                    RS = 1 - TS
                    RP = 1 - TP
                TiT = 0.5 * (TP + TS)
                DiT = (TP - TS) / (TP + TS)
                ZiT = (1. - DiT ** 2) ** 0.5
                TiR = 0.5 * (RP + RS)
                DiR = (RP - RS) / (RP + RS)
                ZiR = (1. - DiR ** 2) ** 0.5
                CosT = np.cos(np.deg2rad(RetT))
                SinT = np.sin(np.deg2rad(RetT))
                CosR = np.cos(np.deg2rad(RetR))
                SinR = np.sin(np.deg2rad(RetR))

                # cleaning pol-filter
                DaT = (1 - ERaT) / (1 + ERaT)
                DaR = (1 - ERaR) / (1 + ERaR)
                TaT = 0.5 * (1 + ERaT)
                TaR = 0.5 * (1 + ERaR)

                S2aT = np.sin(np.deg2rad(h * 2 * RotaT))
                C2aT = np.cos(np.deg2rad(2 * RotaT))
                S2aR = np.sin(np.deg2rad(h * 2 * RotaR))
                C2aR = np.cos(np.deg2rad(2 * RotaR))

                # Analyzer As before the PBS Eq. D.5; combined PBS and cleaning pol-filter
                ATPT = (1 + C2aT * DaT * DiT) # unpolarized transmission correction
                TTa = TiT * TaT * ATPT # unpolarized transmission   
                ATP1 = 1
                ATP2 = Y * (DiT + C2aT * DaT) / ATPT
                ATP3 = Y * S2aT * DaT * ZiT * CosT / ATPT
                ATP4 = S2aT * DaT * ZiT * SinT / ATPT
                ATP = np.array([ATP1, ATP2, ATP3, ATP4])
                DTa = ATP2 * Y  

                ARPT = (1 + C2aR * DaR * DiR) # unpolarized transmission correction
                TRa = TiR * TaR * ARPT # unpolarized transmission   
                ARP1 = 1
                ARP2 = Y * (DiR + C2aR * DaR) / ARPT
                ARP3 = Y * S2aR * DaR * ZiR * CosR / ARPT
                ARP4 = S2aR * DaR * ZiR * SinR / ARPT
                ARP = np.array([ARP1, ARP2, ARP3, ARP4])
                DRa = ARP2 * Y

                # ---- Calculate signals and correction parameters for diffeent locations and calibrators
                if LocC == 4:  # Calibrator before the PBS
                    # print("Calibrator location not implemented yet")

                    # S2ge = np.sin(np.deg2rad(2*RotO + h*2*RotC))
                    # C2ge = np.cos(np.deg2rad(2*RotO + h*2*RotC))
                    S2e = np.sin(np.deg2rad(h * 2 * RotC))
                    C2e = np.cos(np.deg2rad(2 * RotC))
                    # rotated AinP by epsilon Eq. C.3
                    ATP2e = C2e * ATP2 + S2e * ATP3
                    ATP3e = C2e * ATP3 - S2e * ATP2
                    ARP2e = C2e * ARP2 + S2e * ARP3
                    ARP3e = C2e * ARP3 - S2e * ARP2
                    ATPe = np.array([ATP1, ATP2e, ATP3e, ATP4])
                    ARPe = np.array([ARP1, ARP2e, ARP3e, ARP4])
                    # Stokes Input Vector before the polarising beam splitter Eq. E.31
                    A = C2g * QinE - S2g * UinE
                    B = S2g * QinE + C2g * UinE
                    # C = (WiO*aCal*B + ZiO*SinO*(1-2*aCal)*VinE)
                    Co = ZiO * SinO * VinE
                    Ca = (WiO * B - 2 * ZiO * SinO * VinE)
                    # C = Co + aCal*Ca
                    # IinP = (IinE + DiO*aCal*A)
                    # QinP = (C2g*DiO*IinE + aCal*QinE - S2g*C)
                    # UinP = (S2g*DiO*IinE - aCal*UinE + C2g*C)
                    # VinP = (ZiO*SinO*aCal*B + ZiO*CosO*(1-2*aCal)*VinE)
                    IinPo = IinE
                    QinPo = (C2g * DiO * IinE - S2g * Co)
                    UinPo = (S2g * DiO * IinE + C2g * Co)
                    VinPo = ZiO * CosO * VinE

                    IinPa = DiO * A
                    QinPa = QinE - S2g * Ca
                    UinPa = -UinE + C2g * Ca
                    VinPa = ZiO * (SinO * B - 2 * CosO * VinE)

                    IinP = IinPo + aCal * IinPa
                    QinP = QinPo + aCal * QinPa
                    UinP = UinPo + aCal * UinPa
                    VinP = VinPo + aCal * VinPa
                    # Stokes Input Vector before the polarising beam splitter rotated by epsilon Eq. C.3
                    # QinPe = C2e*QinP + S2e*UinP
                    # UinPe = C2e*UinP - S2e*QinP
                    QinPoe = C2e * QinPo + S2e * UinPo
                    UinPoe = C2e * UinPo - S2e * QinPo
                    QinPae = C2e * QinPa + S2e * UinPa
                    UinPae = C2e * UinPa - S2e * QinPa
                    QinPe = C2e * QinP + S2e * UinP
                    UinPe = C2e * UinP - S2e * QinP

                    # Calibration signals and Calibration correction K from measurements with LDRCal / aCal
                    if (TypeC == 2) or (TypeC == 1):  # rotator calibration Eq. C.4
                        # parameters for calibration with aCal
                        AT = ATP1 * IinP + h * ATP4 * VinP
                        BT = ATP3e * QinP - h * ATP2e * UinP
                        AR = ARP1 * IinP + h * ARP4 * VinP
                        BR = ARP3e * QinP - h * ARP2e * UinP
                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                            IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                            GT = np.dot(ATP, IS1)
                            GR = np.dot(ARP, IS1)
                            HT = np.dot(ATP, IS2)
                            HR = np.dot(ARP, IS2)
                        else:
                            IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                            IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                            GT = np.dot(ATPe, IS1)
                            GR = np.dot(ARPe, IS1)
                            HT = np.dot(ATPe, IS2)
                            HR = np.dot(ARPe, IS2)
                    elif (TypeC == 3) or (TypeC == 4):  # linear polariser calibration Eq. C.5
                        # parameters for calibration with aCal
                        AT = ATP1 * IinP + ATP3e * UinPe + ZiC * CosC * (ATP2e * QinPe + ATP4 * VinP)
                        BT = DiC * (ATP1 * UinPe + ATP3e * IinP) - ZiC * SinC * (ATP2e * VinP - ATP4 * QinPe)
                        AR = ARP1 * IinP + ARP3e * UinPe + ZiC * CosC * (ARP2e * QinPe + ARP4 * VinP)
                        BR = DiC * (ARP1 * UinPe + ARP3e * IinP) - ZiC * SinC * (ARP2e * VinP - ARP4 * QinPe)
                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                            IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                            GT = np.dot(ATP, IS1)
                            GR = np.dot(ARP, IS1)
                            HT = np.dot(ATP, IS2)
                            HR = np.dot(ARP, IS2)
                        else:
                            IS1e = np.array(
                                [IinPo + DiC * QinPoe, DiC * IinPo + QinPoe, ZiC * (CosC * UinPoe + SinC * VinPo),
                                 -ZiC * (SinC * UinPoe - CosC * VinPo)])
                            IS2e = np.array(
                                [IinPa + DiC * QinPae, DiC * IinPa + QinPae, ZiC * (CosC * UinPae + SinC * VinPa),
                                 -ZiC * (SinC * UinPae - CosC * VinPa)])
                            GT = np.dot(ATPe, IS1e)
                            GR = np.dot(ARPe, IS1e)
                            HT = np.dot(ATPe, IS2e)
                            HR = np.dot(ARPe, IS2e)
                    elif (TypeC == 6):  # diattenuator calibration +-22.5° rotated_diattenuator_X22x5deg.odt
                        # parameters for calibration with aCal
                        AT = ATP1 * IinP + sqr05 * DiC * (ATP1 * QinPe + ATP2e * IinP) + (1 - 0.5 * WiC) * (
                        ATP2e * QinPe + ATP3e * UinPe) + ZiC * (
                        sqr05 * SinC * (ATP3e * VinP - ATP4 * UinPe) + ATP4 * CosC * VinP)
                        BT = sqr05 * DiC * (ATP1 * UinPe + ATP3e * IinP) + 0.5 * WiC * (
                        ATP2e * UinPe + ATP3e * QinPe) - sqr05 * ZiC * SinC * (ATP2e * VinP - ATP4 * QinPe)
                        AR = ARP1 * IinP + sqr05 * DiC * (ARP1 * QinPe + ARP2e * IinP) + (1 - 0.5 * WiC) * (
                        ARP2e * QinPe + ARP3e * UinPe) + ZiC * (
                        sqr05 * SinC * (ARP3e * VinP - ARP4 * UinPe) + ARP4 * CosC * VinP)
                        BR = sqr05 * DiC * (ARP1 * UinPe + ARP3e * IinP) + 0.5 * WiC * (
                        ARP2e * UinPe + ARP3e * QinPe) - sqr05 * ZiC * SinC * (ARP2e * VinP - ARP4 * QinPe)
                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            IS1 = np.array([IinPo, QinPo, UinPo, VinPo])
                            IS2 = np.array([IinPa, QinPa, UinPa, VinPa])
                            GT = np.dot(ATP, IS1)
                            GR = np.dot(ARP, IS1)
                            HT = np.dot(ATP, IS2)
                            HR = np.dot(ARP, IS2)
                        else:
                            IS1e = np.array(
                                [IinPo + DiC * QinPoe, DiC * IinPo + QinPoe, ZiC * (CosC * UinPoe + SinC * VinPo),
                                 -ZiC * (SinC * UinPoe - CosC * VinPo)])
                            IS2e = np.array(
                                [IinPa + DiC * QinPae, DiC * IinPa + QinPae, ZiC * (CosC * UinPae + SinC * VinPa),
                                 -ZiC * (SinC * UinPae - CosC * VinPa)])
                            GT = np.dot(ATPe, IS1e)
                            GR = np.dot(ARPe, IS1e)
                            HT = np.dot(ATPe, IS2e)
                            HR = np.dot(ARPe, IS2e)
                    else:
                        print("Calibrator not implemented yet")
                        sys.exit()

                elif LocC == 3:  # C before receiver optics Eq.57

                    # S2ge = np.sin(np.deg2rad(2*RotO - 2*RotC))
                    # C2ge = np.cos(np.deg2rad(2*RotO - 2*RotC))
                    S2e = np.sin(np.deg2rad(2 * RotC))
                    C2e = np.cos(np.deg2rad(2 * RotC))

                    # AS with C before the receiver optics (see document rotated_diattenuator_X22x5deg.odt)
                    AF1 = np.array([1, C2g * DiO, S2g * DiO, 0])
                    AF2 = np.array([C2g * DiO, 1 - S2g ** 2 * WiO, S2g * C2g * WiO, -S2g * ZiO * SinO])
                    AF3 = np.array([S2g * DiO, S2g * C2g * WiO, 1 - C2g ** 2 * WiO, C2g * ZiO * SinO])
                    AF4 = np.array([0, S2g * SinO, -C2g * SinO, CosO])

                    ATF = (ATP1 * AF1 + ATP2 * AF2 + ATP3 * AF3 + ATP4 * AF4)
                    ARF = (ARP1 * AF1 + ARP2 * AF2 + ARP3 * AF3 + ARP4 * AF4)
                    ATF1 = ATF[0]
                    ATF2 = ATF[1]
                    ATF3 = ATF[2]
                    ATF4 = ATF[3]
                    ARF1 = ARF[0]
                    ARF2 = ARF[1]
                    ARF3 = ARF[2]
                    ARF4 = ARF[3]

                    # rotated AinF by epsilon
                    ATF2e = C2e * ATF[1] + S2e * ATF[2]
                    ATF3e = C2e * ATF[2] - S2e * ATF[1]
                    ARF2e = C2e * ARF[1] + S2e * ARF[2]
                    ARF3e = C2e * ARF[2] - S2e * ARF[1]

                    ATFe = np.array([ATF1, ATF2e, ATF3e, ATF4])
                    ARFe = np.array([ARF1, ARF2e, ARF3e, ARF4])

                    QinEe = C2e * QinE + S2e * UinE
                    UinEe = C2e * UinE - S2e * QinE

                    # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
                    IinF = IinE
                    QinF = aCal * QinE
                    UinF = -aCal * UinE
                    VinF = (1. - 2. * aCal) * VinE

                    IinFo = IinE
                    QinFo = 0.
                    UinFo = 0.
                    VinFo = VinE

                    IinFa = 0.
                    QinFa = QinE
                    UinFa = -UinE
                    VinFa = -2. * VinE

                    # Stokes Input Vector before receiver optics rotated by epsilon Eq. C.3
                    QinFe = C2e * QinF + S2e * UinF
                    UinFe = C2e * UinF - S2e * QinF
                    QinFoe = C2e * QinFo + S2e * UinFo
                    UinFoe = C2e * UinFo - S2e * QinFo
                    QinFae = C2e * QinFa + S2e * UinFa
                    UinFae = C2e * UinFa - S2e * QinFa

                    # Calibration signals and Calibration correction K from measurements with LDRCal / aCal
                    if (TypeC == 2) or (TypeC == 1):  # rotator calibration Eq. C.4
                        AT = ATF1 * IinF + ATF4 * h * VinF
                        BT = ATF3e * QinF - ATF2e * h * UinF
                        AR = ARF1 * IinF + ARF4 * h * VinF
                        BR = ARF3e * QinF - ARF2e * h * UinF

                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):
                            GT = ATF1 * IinE + ATF4 * VinE
                            GR = ARF1 * IinE + ARF4 * VinE
                            HT = ATF2 * QinE - ATF3 * UinE - ATF4 * 2 * VinE
                            HR = ARF2 * QinE - ARF3 * UinE - ARF4 * 2 * VinE
                        else:
                            GT = ATF1 * IinE + ATF4 * h * VinE
                            GR = ARF1 * IinE + ARF4 * h * VinE
                            HT = ATF2e * QinE - ATF3e * h * UinE - ATF4 * h * 2 * VinE
                            HR = ARF2e * QinE - ARF3e * h * UinE - ARF4 * h * 2 * VinE

                    elif (TypeC == 3) or (TypeC == 4):  # linear polariser calibration Eq. C.5
                        # p = +45°, m = -45°
                        IF1e = np.array([IinF, ZiC * CosC * QinFe, UinFe, ZiC * CosC * VinF])
                        IF2e = np.array([DiC * UinFe, -ZiC * SinC * VinF, DiC * IinF, ZiC * SinC * QinFe])

                        AT = np.dot(ATFe, IF1e)
                        AR = np.dot(ARFe, IF1e)
                        BT = np.dot(ATFe, IF2e)
                        BR = np.dot(ARFe, IF2e)

                        # Correction parameters for normal measurements; they are independent of LDR  --- the same as for TypeC = 6
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            IS1 = np.array([IinE, 0, 0, VinE])
                            IS2 = np.array([0, QinE, -UinE, -2 * VinE])

                            GT = np.dot(ATF, IS1)
                            GR = np.dot(ARF, IS1)
                            HT = np.dot(ATF, IS2)
                            HR = np.dot(ARF, IS2)
                        else:
                            IS1e = np.array(
                                [IinFo + DiC * QinFoe, DiC * IinFo + QinFoe, ZiC * (CosC * UinFoe + SinC * VinFo),
                                 -ZiC * (SinC * UinFoe - CosC * VinFo)])
                            IS2e = np.array(
                                [IinFa + DiC * QinFae, DiC * IinFa + QinFae, ZiC * (CosC * UinFae + SinC * VinFa),
                                 -ZiC * (SinC * UinFae - CosC * VinFa)])
                            GT = np.dot(ATFe, IS1e)
                            GR = np.dot(ARFe, IS1e)
                            HT = np.dot(ATFe, IS2e)
                            HR = np.dot(ARFe, IS2e)

                    elif (TypeC == 6):  # diattenuator calibration +-22.5° rotated_diattenuator_X22x5deg.odt
                        # p = +22.5°, m = -22.5°
                        IF1e = np.array([IinF + sqr05 * DiC * QinFe, sqr05 * DiC * IinF + (1 - 0.5 * WiC) * QinFe,
                                         (1 - 0.5 * WiC) * UinFe + sqr05 * ZiC * SinC * VinF,
                                         -sqr05 * ZiC * SinC * UinFe + ZiC * CosC * VinF])
                        IF2e = np.array([sqr05 * DiC * UinFe, 0.5 * WiC * UinFe - sqr05 * ZiC * SinC * VinF,
                                         sqr05 * DiC * IinF + 0.5 * WiC * QinFe, sqr05 * ZiC * SinC * QinFe])

                        AT = np.dot(ATFe, IF1e)
                        AR = np.dot(ARFe, IF1e)
                        BT = np.dot(ATFe, IF2e)
                        BR = np.dot(ARFe, IF2e)

                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            # IS1 = np.array([IinE,0,0,VinE])
                            # IS2 = np.array([0,QinE,-UinE,-2*VinE])
                            IS1 = np.array([IinFo, 0, 0, VinFo])
                            IS2 = np.array([0, QinFa, UinFa, VinFa])
                            GT = np.dot(ATF, IS1)
                            GR = np.dot(ARF, IS1)
                            HT = np.dot(ATF, IS2)
                            HR = np.dot(ARF, IS2)
                        else:
                            # IS1e = np.array([IinE,DiC*IinE,ZiC*SinC*VinE,ZiC*CosC*VinE])
                            # IS2e = np.array([DiC*QinEe,QinEe,-ZiC*(CosC*UinEe+2*SinC*VinE),ZiC*(SinC*UinEe-2*CosC*VinE)])
                            IS1e = np.array(
                                [IinFo + DiC * QinFoe, DiC * IinFo + QinFoe, ZiC * (CosC * UinFoe + SinC * VinFo),
                                 -ZiC * (SinC * UinFoe - CosC * VinFo)])
                            IS2e = np.array(
                                [IinFa + DiC * QinFae, DiC * IinFa + QinFae, ZiC * (CosC * UinFae + SinC * VinFa),
                                 -ZiC * (SinC * UinFae - CosC * VinFa)])
                            GT = np.dot(ATFe, IS1e)
                            GR = np.dot(ARFe, IS1e)
                            HT = np.dot(ATFe, IS2e)
                            HR = np.dot(ARFe, IS2e)


                    else:
                        print('Calibrator not implemented yet')
                        sys.exit()

                elif LocC == 2:  # C behind emitter optics Eq.57
                    # print("Calibrator location not implemented yet")
                    S2e = np.sin(np.deg2rad(2 * RotC))
                    C2e = np.cos(np.deg2rad(2 * RotC))

                    # AS with C before the receiver optics (see document rotated_diattenuator_X22x5deg.odt)
                    AF1 = np.array([1, C2g * DiO, S2g * DiO, 0])
                    AF2 = np.array([C2g * DiO, 1 - S2g ** 2 * WiO, S2g * C2g * WiO, -S2g * ZiO * SinO])
                    AF3 = np.array([S2g * DiO, S2g * C2g * WiO, 1 - C2g ** 2 * WiO, C2g * ZiO * SinO])
                    AF4 = np.array([0, S2g * SinO, -C2g * SinO, CosO])

                    ATF = (ATP1 * AF1 + ATP2 * AF2 + ATP3 * AF3 + ATP4 * AF4)
                    ARF = (ARP1 * AF1 + ARP2 * AF2 + ARP3 * AF3 + ARP4 * AF4)
                    ATF1 = ATF[0]
                    ATF2 = ATF[1]
                    ATF3 = ATF[2]
                    ATF4 = ATF[3]
                    ARF1 = ARF[0]
                    ARF2 = ARF[1]
                    ARF3 = ARF[2]
                    ARF4 = ARF[3]

                    # AS with C behind the emitter  --------------------------------------------
                    # terms without aCal
                    ATE1o, ARE1o = ATF1, ARF1
                    ATE2o, ARE2o = 0., 0.
                    ATE3o, ARE3o = 0., 0.
                    ATE4o, ARE4o = ATF4, ARF4
                    # terms with aCal
                    ATE1a, ARE1a = 0., 0.
                    ATE2a, ARE2a = ATF2, ARF2
                    ATE3a, ARE3a = -ATF3, -ARF3
                    ATE4a, ARE4a = -2 * ATF4, -2 * ARF4
                    # rotated AinEa by epsilon
                    ATE2ae = C2e * ATF2 + S2e * ATF3
                    ATE3ae = -S2e * ATF2 - C2e * ATF3
                    ARE2ae = C2e * ARF2 + S2e * ARF3
                    ARE3ae = -S2e * ARF2 - C2e * ARF3

                    ATE1 = ATE1o
                    ATE2e = aCal * ATE2ae
                    ATE3e = aCal * ATE3ae
                    ATE4 = (1 - 2 * aCal) * ATF4
                    ARE1 = ARE1o
                    ARE2e = aCal * ARE2ae
                    ARE3e = aCal * ARE3ae
                    ARE4 = (1 - 2 * aCal) * ARF4

                    # rotated IinE
                    QinEe = C2e * QinE + S2e * UinE
                    UinEe = C2e * UinE - S2e * QinE

                    # --- Calibration signals and Calibration correction K from measurements with LDRCal / aCal
                    if (TypeC == 2) or (TypeC == 1):  # +++++++++ rotator calibration Eq. C.4
                        AT = ATE1o * IinE + (ATE4o + aCal * ATE4a) * h * VinE
                        BT = aCal * (ATE3ae * QinEe - ATE2ae * h * UinEe)
                        AR = ARE1o * IinE + (ARE4o + aCal * ARE4a) * h * VinE
                        BR = aCal * (ARE3ae * QinEe - ARE2ae * h * UinEe)

                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):
                            # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
                            GT = ATE1o * IinE + ATE4o * h * VinE
                            GR = ARE1o * IinE + ARE4o * h * VinE
                            HT = ATE2a * QinE + ATE3a * h * UinEe + ATE4a * h * VinE
                            HR = ARE2a * QinE + ARE3a * h * UinEe + ARE4a * h * VinE
                        else:
                            GT = ATE1o * IinE + ATE4o * h * VinE
                            GR = ARE1o * IinE + ARE4o * h * VinE
                            HT = ATE2ae * QinE + ATE3ae * h * UinEe + ATE4a * h * VinE
                            HR = ARE2ae * QinE + ARE3ae * h * UinEe + ARE4a * h * VinE

                    elif (TypeC == 3) or (TypeC == 4):  # +++++++++ linear polariser calibration Eq. C.5
                        # p = +45°, m = -45°
                        AT = ATE1 * IinE + ZiC * CosC * (ATE2e * QinEe + ATE4 * VinE) + ATE3e * UinEe
                        BT = DiC * (ATE1 * UinEe + ATE3e * IinE) + ZiC * SinC * (ATE4 * QinEe - ATE2e * VinE)
                        AR = ARE1 * IinE + ZiC * CosC * (ARE2e * QinEe + ARE4 * VinE) + ARE3e * UinEe
                        BR = DiC * (ARE1 * UinEe + ARE3e * IinE) + ZiC * SinC * (ARE4 * QinEe - ARE2e * VinE)

                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):
                            # Stokes Input Vector before receiver optics Eq. E.19 (after atmosphere F)
                            GT = ATE1o * IinE + ATE4o * VinE
                            GR = ARE1o * IinE + ARE4o * VinE
                            HT = ATE2a * QinE + ATE3a * UinE + ATE4a * VinE
                            HR = ARE2a * QinE + ARE3a * UinE + ARE4a * VinE
                        else:
                            D = IinE + DiC * QinEe
                            A = DiC * IinE + QinEe
                            B = ZiC * (CosC * UinEe + SinC * VinE)
                            C = -ZiC * (SinC * UinEe - CosC * VinE)
                            GT = ATE1o * D + ATE4o * C
                            GR = ARE1o * D + ARE4o * C
                            HT = ATE2a * A + ATE3a * B + ATE4a * C
                            HR = ARE2a * A + ARE3a * B + ARE4a * C

                    elif (TypeC == 6):  # real HWP calibration +-22.5° rotated_diattenuator_X22x5deg.odt
                        # p = +22.5°, m = -22.5°
                        IE1e = np.array([IinE + sqr05 * DiC * QinEe, sqr05 * DiC * IinE + (1 - 0.5 * WiC) * QinEe,
                                         (1 - 0.5 * WiC) * UinEe + sqr05 * ZiC * SinC * VinE,
                                         -sqr05 * ZiC * SinC * UinEe + ZiC * CosC * VinE])
                        IE2e = np.array([sqr05 * DiC * UinEe, 0.5 * WiC * UinEe - sqr05 * ZiC * SinC * VinE,
                                         sqr05 * DiC * IinE + 0.5 * WiC * QinEe, sqr05 * ZiC * SinC * QinEe])
                        ATEe = np.array([ATE1, ATE2e, ATE3e, ATE4])
                        AREe = np.array([ARE1, ARE2e, ARE3e, ARE4])
                        AT = np.dot(ATEe, IE1e)
                        AR = np.dot(AREe, IE1e)
                        BT = np.dot(ATEe, IE2e)
                        BR = np.dot(AREe, IE2e)

                        # Correction parameters for normal measurements; they are independent of LDR
                        if (not RotationErrorEpsilonForNormalMeasurements):  # calibrator taken out
                            GT = ATE1o * IinE + ATE4o * VinE
                            GR = ARE1o * IinE + ARE4o * VinE
                            HT = ATE2a * QinE + ATE3a * UinE + ATE4a * VinE
                            HR = ARE2a * QinE + ARE3a * UinE + ARE4a * VinE
                        else:
                            D = IinE + DiC * QinEe
                            A = DiC * IinE + QinEe
                            B = ZiC * (CosC * UinEe + SinC * VinE)
                            C = -ZiC * (SinC * UinEe - CosC * VinE)
                            GT = ATE1o * D + ATE4o * C
                            GR = ARE1o * D + ARE4o * C
                            HT = ATE2a * A + ATE3a * B + ATE4a * C
                            HR = ARE2a * A + ARE3a * B + ARE4a * C
                    else:
                        print('Calibrator not implemented yet')
                        sys.exit()

                for iTCalT, iTCalR, iNCalTp, iNCalTm, iNCalRp, iNCalRm, iNIt, iNIr \
                        in [
                    (iTCalT, iTCalR, iNCalTp, iNCalTm, iNCalRp, iNCalRm, iNIt, iNIr)
                    for iTCalT in range(-nTCalT, nTCalT + 1) # Etax
                    for iTCalR in range(-nTCalR, nTCalR + 1) # Etax
                    for iNCalTp in range(-nNCal, nNCal + 1) # noise error of calibration signals => Etax
                    for iNCalTm in range(-nNCal, nNCal + 1) # noise error of calibration signals => Etax
                    for iNCalRp in range(-nNCal, nNCal + 1) # noise error of calibration signals => Etax
                    for iNCalRm in range(-nNCal, nNCal + 1) # noise error of calibration signals => Etax
                    for iNIt in range(-nNI, nNI + 1)
                    for iNIr in range(-nNI, nNI + 1)]:

                    # Calibration signals with aCal => Determination of the correction K of the real calibration factor
                    IoutTp = TTa * TiC * TiO * TiE * (AT + BT)
                    IoutTm = TTa * TiC * TiO * TiE * (AT - BT)
                    IoutRp = TRa * TiC * TiO * TiE * (AR + BR)
                    IoutRm = TRa * TiC * TiO * TiE * (AR - BR)

                    if nTCalT > 0: TCalT = TCalT0 + iTCalT * dTCalT / nTCalT
                    if nTCalR > 0: TCalR = TCalR0 + iTCalR * dTCalR / nTCalR
                    # signal noise errors
                        # ----- random error calculation ----------
                        # noise must be calculated from/with the actually measured signals; influence of TCalT, TCalR errors on nouse are not considered ?
                        # actually measured signals are in input file and don't change
                        # relative standard deviation of calibration signals with LDRcal; assumed to be statisitcally independent
                        # error nNCal: one-sigma in steps to left and right for calibration signals
                    if nNCal > 0:
                        if (CalcFrom0deg):
                            dIoutTp = (NCalT * IoutTp) ** -0.5
                            dIoutTm = (NCalT * IoutTm) ** -0.5
                            dIoutRp = (NCalR * IoutRp) ** -0.5
                            dIoutRm = (NCalR * IoutRm) ** -0.5
                        else:
                            dIoutTp = dIoutTp0 * (IoutTp / IoutTp0)
                            dIoutTm = dIoutTm0 * (IoutTm / IoutTm0)
                            dIoutRp = dIoutRp0 * (IoutRp / IoutRp0)
                            dIoutRm = dIoutRm0 * (IoutRm / IoutRm0)
                        # print(iTCalT, iTCalR, iNCalTp, iNCalTm, iNCalRp, iNCalRm, iNIt, iNIr, IoutTp, dIoutTp)
                        IoutTp = IoutTp * (1 + iNCalTp * dIoutTp / nNCal)
                        IoutTm = IoutTm * (1 + iNCalTm * dIoutTm / nNCal)
                        IoutRp = IoutRp * (1 + iNCalRp * dIoutRp / nNCal)
                        IoutRm = IoutRm * (1 + iNCalRm * dIoutRm / nNCal)

                    IoutTp = IoutTp * TCalT / TCalT0
                    IoutTm = IoutTm * TCalT / TCalT0
                    IoutRp = IoutRp * TCalR / TCalR0
                    IoutRm = IoutRm * TCalR / TCalR0
                    # --- Results and Corrections; electronic etaR and etaT are assumed to be 1 for true and assumed true systems
                    # calibration factor
                    Eta = (TRa / TTa) # = TRa / TTa; Eta = Eta*/K  Eq. 84; corrected according to the papers supplement Eqs. (S.10.10.1) ff
                    # possibly real calibration factor
                    Etapx = IoutRp / IoutTp
                    Etamx = IoutRm / IoutTm
                    Etax = (Etapx * Etamx) ** 0.5
                    K = Etax / Eta
                    # print("{0:6.3f},{1:6.3f},{2:6.3f},{3:6.3f},{4:6.3f},{5:6.3f},{6:6.3f},{7:6.3f},{8:6.3f},{9:6.3f},{10:6.3f}".format(AT, BT, AR, BR, DiC, ZiC, RetO, TP, TS, Kp, Km))
                    # print("{0:6.3f},{1:6.3f},{2:6.3f},{3:6.3f}".format(DiC, ZiC, Kp, Km))

                    #  For comparison with Volkers Libreoffice Müller Matrix spreadsheet
                    # Eta_test_p = (IoutRp/IoutTp)
                    # Eta_test_m = (IoutRm/IoutTm)
                    # Eta_test = (Eta_test_p*Eta_test_m)**0.5
                    '''
                    for iIt, iIr \
                            in [(iIt, iIr)
                                for iIt in range(-nNI, nNI + 1)
                                for iIr in range(-nNI, nNI + 1)]:
                    '''

                    iN = iN + 1
                    if (iN == 10001):
                        ctime = clock()
                        print(" estimated time ", "{0:4.2f}".format(N / 10000 * (ctime - atime)), "sec ")  # , end="")
                        print("\r elapsed time ", "{0:5.0f}".format((ctime - atime)), "sec ", end="\r")
                    ctime = clock()
                    if ((ctime - dtime) > 10):
                        print("\r elapsed time ", "{0:5.0f}".format((ctime - atime)), "sec ", end="\r")
                        dtime = ctime

                    # *** loop for different real LDRs **********************************************************************
                    iLDR = -1
                    for LDRTrue in LDRrange:
                        iLDR = iLDR + 1
                        atrue = (1 - LDRTrue) / (1 + LDRTrue)
                        # ----- Forward simulated signals and LDRsim with atrue; from input file; not considering TiC.
                        It = TTa * TiO * TiE * (GT + atrue * HT)  # TaT*TiT*TiC*TiO*IinL*(GT+atrue*HT)
                        Ir = TRa * TiO * TiE * (GR + atrue * HR)  # TaR*TiR*TiC*TiO*IinL*(GR+atrue*HR)
                        # # signal noise errors; standard deviation of signals; assumed to be statisitcally independent
                        # because the signals depend on LDRtrue, the errors dIt and dIr must be calculated for each LDRtrue
                        if (CalcFrom0deg):
                            dIt = ((NCalT * It / IoutTp * NILfac / TCalT) ** -0.5)
                            dIr = ((NCalR * Ir / IoutRp * NILfac / TCalR) ** -0.5)
                        else:
                            dIt = ((NCalT * 2 * NILfac / TCalT ) ** -0.5) * It
                            dIr = ((NCalR * 2 * NILfac / TCalR) ** -0.5) * Ir
                        # error nNI: one-sigma in steps to left and right for 0° signals
                        if nNI > 0:
                            It = It * (1 + iNIt * dIt / nNI)
                            Ir = Ir * (1 + iNIr * dIr / nNI)

                        # LDRsim = 1/Eta*Ir/It  # simulated LDR* with Y from input file
                        LDRsim = Ir / It  # simulated uncorrected LDR with Y from input file

                        # ----- Backward correction
                        # Corrected LDRCorr  with assumed true G0,H0,K0,Eta0 from forward simulated (real) LDRsim(atrue)
                        LDRCorr = (LDRsim / (Etax / K0) * (GT0 + HT0) - (GR0 + HR0)) / ((GR0 - HR0) - LDRsim / (Etax / K0) * (GT0 - HT0))

                        # The following is a test whether the equations for calibration Etax and normal  signal (GHK, LDRsim) are consistent
                        # LDRCorr = (LDRsim / Eta * (GT + HT) - (GR + HR)) / ((GR - HR) - LDRsim / Eta * (GT - HT))
                        # Without any correction
                        LDRunCorr = (LDRsim / Etax * (GT / abs(GT) + HT / abs(HT)) - (GR / abs(GR) + HR / abs(HR))) / ((GR / abs(GR) - HR / abs(HR)) - LDRsim / Etax * (GT / abs(GT) - HT / abs(HT)))


                        '''
                        # -- F11corr from It and Ir and calibration EtaX
                        Text1 = "!!! EXPERIMENTAL !!!  F11corr from It and Ir with calibration EtaX: x-axis: F11corr(LDRtrue) / F11corr(LDRtrue = 0.004) - 1"
                        F11corr = 1 / (TiO * TiE) * (
                        (HR0 * Etax / K0 * It / TTa - HT0 * Ir / TRa) / (HR0 * GT0 - HT0 * GR0))  # IL = 1  Eq.(64); Etax/K0 = Eta0.
                        '''
                        # Corrected F11corr  with assumed true G0,H0,K0 from forward simulated (real) It and Ir (atrue)
                        Text1 = "!!! EXPERIMENTAL !!!  F11corr from real It and Ir with real calibration EtaX: x-axis: F11corr(LDRtrue) / aF11sim0(LDRtrue) - 1"
                        F11corr = 1 / (TiO * TiE) * (
                        (HR0 * Etax / K0 * It / TTa - HT0 * Ir / TRa) / (HR0 * GT0 - HT0 * GR0))  # IL = 1  Eq.(64); Etax/K0 = Eta0.

                        # Text1 = "F11corr from It and Ir without corrections but with calibration EtaX: x-axis: F11corr(LDRtrue) devided by F11corr(LDRtrue = 0.004)"
                        # F11corr = 0.5/(TiO*TiE)*(Etax*It/TTa+Ir/TRa)    # IL = 1  Eq.(64)

                        # -- It from It only with atrue without corrections - for BERTHA (and PollyXTs)
                        # Text1 = " x-axis: IT(LDRtrue) / IT(LDRtrue = 0.004) - 1"
                        # F11corr = It/(TaT*TiT*TiO*TiE)   #/(TaT*TiT*TiO*TiE*(GT0+atrue*HT0))
                        # ! see below line 1673ff

                        aF11corr[iLDR, iN] = F11corr
                        aLDRcorr[iLDR, iN] = LDRCorr # LDRCorr # LDRsim # for test only
                        # aPLDR[iLDR, iN] = CalcPLDR(LDRCorr, BSR[iLDR], LDRm0)
                        aEtax[iLDR, iN] = Etax

                        aGHK[0, iN] = GR
                        aGHK[1, iN] = GT
                        aGHK[2, iN] = HR
                        aGHK[3, iN] = HT
                        aGHK[4, iN] = K

                        aLDRCal[iN] = iLDRCal
                        aDOLP[iN] = iDOLP
                        aERaT[iN] = iERaT
                        aERaR[iN] = iERaR
                        aRotaT[iN] = iRotaT
                        aRotaR[iN] = iRotaR
                        aRetT[iN] = iRetT
                        aRetR[iN] = iRetR

                        aRotL[iN] = iRotL
                        aRotE[iN] = iRotE
                        aRetE[iN] = iRetE
                        aRotO[iN] = iRotO
                        aRetO[iN] = iRetO
                        aRotC[iN] = iRotC
                        aRetC[iN] = iRetC
                        aDiO[iN] = iDiO
                        aDiE[iN] = iDiE
                        aDiC[iN] = iDiC
                        aTP[iN] = iTP
                        aTS[iN] = iTS
                        aRP[iN] = iRP
                        aRS[iN] = iRS
                        aTCalT[iN] = iTCalT
                        aTCalR[iN] = iTCalR

                        aNCalTp[iN] = iNCalTp   # IoutTp, IoutTm, IoutRp, IoutRm => Etax
                        aNCalTm[iN] = iNCalTm   # IoutTp, IoutTm, IoutRp, IoutRm => Etax
                        aNCalRp[iN] = iNCalRp   # IoutTp, IoutTm, IoutRp, IoutRm => Etax
                        aNCalRm[iN] = iNCalRm   # IoutTp, IoutTm, IoutRp, IoutRm => Etax
                        aNIt[iN] = iNIt       # It, Tr
                        aNIr[iN] = iNIr       # It, Tr

    # --- END loop
    btime = clock()
    # print("\r done in      ", "{0:5.0f}".format(btime - atime), "sec.      => producing plots now .... some more seconds ..."),  # , end="\r");
    print(" done in      ", "{0:5.0f}".format(btime - atime), "sec.      => producing plots now .... some more seconds ...")
    # --- Plot -----------------------------------------------------------------
    print("Errors from GHK correction uncertainties:")
    if (sns_loaded):
        sns.set_style("whitegrid")
        sns.set_palette("bright6", 6)
        # for older seaborn versions:
        # sns.set_palette("bright", 6)

    '''
    fig2 = plt.figure()
    plt.plot(aLDRcorr[2,:],'b.')
    plt.plot(aLDRcorr[3,:],'r.')
    plt.plot(aLDRcorr[4,:],'g.')
    #plt.plot(aLDRcorr[6,:],'c.')
    plt.show
    '''

    # Plot LDR
    def PlotSubHist(aVar, aX, X0, daX, iaX, naX):
        # aVar is the name of the parameter and aX is the subset of aLDRcorr which is coloured in the plot
        # example: PlotSubHist("DOLP", aDOLP, DOLP0, dDOLP, iDOLP, nDOLP)
        fig, ax = plt.subplots(nrows=1, ncols=5, sharex=True, sharey=True, figsize=(25, 2))
        iLDR = -1
        for LDRTrue in LDRrange:
            iLDR = iLDR + 1
            LDRmin[iLDR] = np.amin(aLDRcorr[iLDR, :])
            LDRmax[iLDR] = np.amax(aLDRcorr[iLDR, :])
            Rmin = LDRmin[iLDR] * 0.995  # np.min(aLDRcorr[iLDR,:])    * 0.995
            Rmax = LDRmax[iLDR] * 1.005  # np.max(aLDRcorr[iLDR,:])    * 1.005

            # plt.subplot(5,2,iLDR+1)
            plt.subplot(1, 5, iLDR + 1)
            (n, bins, patches) = plt.hist(aLDRcorr[iLDR, :],
                                          bins=100, log=False,
                                          range=[Rmin, Rmax],
                                          alpha=0.5, density=False, color='0.5', histtype='stepfilled')

            for iaX in range(-naX, naX + 1):
                plt.hist(aLDRcorr[iLDR, aX == iaX],
                         range=[Rmin, Rmax],
                         bins=100, log=False, alpha=0.3, density=False, histtype='stepfilled',
                         label=str(round(X0 + iaX * daX / naX, 5)))

                if (iLDR == 2):
                    leg = plt.legend()
                    leg.get_frame().set_alpha(0.1)
                

            plt.tick_params(axis='both', labelsize=9)
            plt.plot([LDRTrue, LDRTrue], [0, np.max(n)], 'r-', lw=2)

        # plt.title(LID + '  ' + aVar, fontsize=18)
        # plt.ylabel('frequency', fontsize=10)
        # plt.xlabel('LDRcorr', fontsize=10)
        # fig.tight_layout()
        fig.suptitle(LID + ' with ' + str(Type[TypeC]) + ' ' + str(Loc[LocC]) + ' - ' + aVar, fontsize=14, y=1.05)
        # plt.show()
        # fig.savefig(LID + '_' + aVar + '.png', dpi=150, bbox_inches='tight', pad_inches=0)
        # plt.close
        return

    # Plot Etax
    def PlotEtax(aVar, aX, X0, daX, iaX, naX):
        # aVar is the name of the parameter and aX is the subset of aLDRcorr which is coloured in the plot
        # example: PlotSubHist("DOLP", aDOLP, DOLP0, dDOLP, iDOLP, nDOLP)
        fig, ax = plt.subplots(nrows=1, ncols=5, sharex=True, sharey=True, figsize=(25, 2))
        iLDR = -1
        for LDRTrue in LDRrange:
            iLDR = iLDR + 1
            Etaxmin[iLDR] = np.amin(aEtax[iLDR, :])
            Etaxmax[iLDR] = np.amax(aEtax[iLDR, :])
            Rmin = Etaxmin[iLDR] * 0.995  # np.min(aLDRcorr[iLDR,:])    * 0.995
            Rmax = Etaxmax[iLDR] * 1.005  # np.max(aLDRcorr[iLDR,:])    * 1.005

            # plt.subplot(5,2,iLDR+1)
            plt.subplot(1, 5, iLDR + 1)
            (n, bins, patches) = plt.hist(aEtax[iLDR, :],
                                          bins=100, log=False,
                                          range=[Rmin, Rmax],
                                          alpha=0.5, density=False, color='0.5', histtype='stepfilled')
            for iaX in range(-naX, naX + 1):
                plt.hist(aEtax[iLDR, aX == iaX],
                         range=[Rmin, Rmax],
                         bins=100, log=False, alpha=0.3, density=False, histtype='stepfilled',
                         label=str(round(X0 + iaX * daX / naX, 5)))
                if (iLDR == 2):
                    leg = plt.legend()
                    leg.get_frame().set_alpha(0.1)
            plt.tick_params(axis='both', labelsize=9)
            plt.plot([Etax0, Etax0], [0, np.max(n)], 'r-', lw=2)
        fig.suptitle('Etax - ' + LID + ' with ' + str(Type[TypeC]) + ' ' + str(Loc[LocC]) + ' - ' + aVar, fontsize=14, y=1.05)
        return

    if (nDOLP > 0): PlotSubHist("DOLP", aDOLP, DOLP0, dDOLP, iDOLP, nDOLP)
    if (nRotL > 0): PlotSubHist("RotL", aRotL, RotL0, dRotL, iRotL, nRotL)
    if (nRetE > 0): PlotSubHist("RetE", aRetE, RetE0, dRetE, iRetE, nRetE)
    if (nRotE > 0): PlotSubHist("RotE", aRotE, RotE0, dRotE, iRotE, nRotE)
    if (nDiE > 0): PlotSubHist("DiE", aDiE, DiE0, dDiE, iDiE, nDiE)
    if (nRetO > 0): PlotSubHist("RetO", aRetO, RetO0, dRetO, iRetO, nRetO)
    if (nRotO > 0): PlotSubHist("RotO", aRotO, RotO0, dRotO, iRotO, nRotO)
    if (nDiO > 0): PlotSubHist("DiO", aDiO, DiO0, dDiO, iDiO, nDiO)
    if (nDiC > 0): PlotSubHist("DiC", aDiC, DiC0, dDiC, iDiC, nDiC)
    if (nRotC > 0): PlotSubHist("RotC", aRotC, RotC0, dRotC, iRotC, nRotC)
    if (nRetC > 0): PlotSubHist("RetC", aRetC, RetC0, dRetC, iRetC, nRetC)
    if (nTP > 0): PlotSubHist("TP", aTP, TP0, dTP, iTP, nTP)
    if (nTS > 0): PlotSubHist("TS", aTS, TS0, dTS, iTS, nTS)
    if (nRP > 0): PlotSubHist("RP", aRP, RP0, dRP, iRP, nRP)
    if (nRS > 0): PlotSubHist("RS", aRS, RS0, dRS, iRS, nRS)
    if (nRetT > 0): PlotSubHist("RetT", aRetT, RetT0, dRetT, iRetT, nRetT)
    if (nRetR > 0): PlotSubHist("RetR", aRetR, RetR0, dRetR, iRetR, nRetR)
    if (nERaT > 0): PlotSubHist("ERaT", aERaT, ERaT0, dERaT, iERaT, nERaT)
    if (nERaR > 0): PlotSubHist("ERaR", aERaR, ERaR0, dERaR, iERaR, nERaR)
    if (nRotaT > 0): PlotSubHist("RotaT", aRotaT, RotaT0, dRotaT, iRotaT, nRotaT)
    if (nRotaR > 0): PlotSubHist("RotaR", aRotaR, RotaR0, dRotaR, iRotaR, nRotaR)
    if (nLDRCal > 0): PlotSubHist("LDRCal", aLDRCal, LDRCal0, dLDRCal, iLDRCal, nLDRCal)
    if (nTCalT > 0): PlotSubHist("TCalT", aTCalT, TCalT0, dTCalT, iTCalT, nTCalT)
    if (nTCalR > 0): PlotSubHist("TCalR", aTCalR, TCalR0, dTCalR, iTCalR, nTCalR)
    if (nNCal > 0): PlotSubHist("CalNoiseTp", aNCalTp, 0, 1, iNCalTp, nNCal)
    if (nNCal > 0): PlotSubHist("CalNoiseTm", aNCalTm, 0, 1, iNCalTm, nNCal)
    if (nNCal > 0): PlotSubHist("CalNoiseRp", aNCalRp, 0, 1, iNCalRp, nNCal)
    if (nNCal > 0): PlotSubHist("CalNoiseRm", aNCalRm, 0, 1, iNCalRm, nNCal)
    if (nNI > 0): PlotSubHist("SigNoiseIt", aNIt, 0, 1, iNIt, nNI)
    if (nNI > 0): PlotSubHist("SigNoiseIr", aNIr, 0, 1, iNIr, nNI)
    plt.show()
    plt.close

    '''
    # --- Plot F11 histograms
    print()
    print(" ############################################################################## ")
    print(Text1)
    print()

    iLDR = 5
    for LDRTrue in LDRrange:
        iLDR = iLDR - 1
        #aF11corr[iLDR,:] = aF11corr[iLDR,:] / aF11corr[0,:] - 1.0
        aF11corr[iLDR,:] = aF11corr[iLDR,:] / aF11sim0[iLDR] - 1.0
    # Plot F11
    def PlotSubHistF11(aVar, aX, X0, daX, iaX, naX):
        fig, ax = plt.subplots(nrows=1, ncols=5, sharex=True, sharey=True, figsize=(25, 2))
        iLDR = -1
        for LDRTrue in LDRrange:
            iLDR = iLDR + 1

            #F11min[iLDR] = np.min(aF11corr[iLDR,:])
            #F11max[iLDR] = np.max(aF11corr[iLDR,:])
            #Rmin = F11min[iLDR] * 0.995 #  np.min(aLDRcorr[iLDR,:])    * 0.995
            #Rmax = F11max[iLDR] * 1.005 #  np.max(aLDRcorr[iLDR,:])    * 1.005

            #Rmin = 0.8
            #Rmax = 1.2

            #plt.subplot(5,2,iLDR+1)
            plt.subplot(1,5,iLDR+1)
            (n, bins, patches) = plt.hist(aF11corr[iLDR,:],
                     bins=100, log=False,
                     alpha=0.5, density=False, color = '0.5', histtype='stepfilled')

            for iaX in range(-naX,naX+1):
                plt.hist(aF11corr[iLDR,aX == iaX],
                         bins=100, log=False, alpha=0.3, density=False, histtype='stepfilled', label = str(round(X0 + iaX*daX/naX,5)))

                if (iLDR == 2): plt.legend()

            plt.tick_params(axis='both', labelsize=9)
            #plt.plot([LDRTrue, LDRTrue], [0, np.max(n)], 'r-', lw=2)

        #plt.title(LID + '  ' + aVar, fontsize=18)
        #plt.ylabel('frequency', fontsize=10)
        #plt.xlabel('LDRcorr', fontsize=10)
        #fig.tight_layout()
        fig.suptitle(LID + '  ' + str(Type[TypeC]) + ' ' + str(Loc[LocC])  + ' - ' + aVar, fontsize=14, y=1.05)
        #plt.show()
        #fig.savefig(LID + '_' + aVar + '.png', dpi=150, bbox_inches='tight', pad_inches=0)
        #plt.close
        return

    if (nDOLP > 0): PlotSubHistF11("DOLP", aDOLP, DOLP0, dDOLP, iDOLP, nDOLP)
    if (nRotL > 0): PlotSubHistF11("RotL", aRotL, RotL0, dRotL, iRotL, nRotL)
    if (nRetE > 0): PlotSubHistF11("RetE", aRetE, RetE0, dRetE, iRetE, nRetE)
    if (nRotE > 0): PlotSubHistF11("RotE", aRotE, RotE0, dRotE, iRotE, nRotE)
    if (nDiE > 0): PlotSubHistF11("DiE", aDiE, DiE0, dDiE, iDiE, nDiE)
    if (nRetO > 0): PlotSubHistF11("RetO", aRetO, RetO0, dRetO, iRetO, nRetO)
    if (nRotO > 0): PlotSubHistF11("RotO", aRotO, RotO0, dRotO, iRotO, nRotO)
    if (nDiO > 0): PlotSubHistF11("DiO", aDiO, DiO0, dDiO, iDiO, nDiO)
    if (nDiC > 0): PlotSubHistF11("DiC", aDiC, DiC0, dDiC, iDiC, nDiC)
    if (nRotC > 0): PlotSubHistF11("RotC", aRotC, RotC0, dRotC, iRotC, nRotC)
    if (nRetC > 0): PlotSubHistF11("RetC", aRetC, RetC0, dRetC, iRetC, nRetC)
    if (nTP > 0): PlotSubHistF11("TP", aTP, TP0, dTP, iTP, nTP)
    if (nTS > 0): PlotSubHistF11("TS", aTS, TS0, dTS, iTS, nTS)
    if (nRP > 0): PlotSubHistF11("RP", aRP, RP0, dRP, iRP, nRP)
    if (nRS > 0): PlotSubHistF11("RS", aRS, RS0, dRS, iRS, nRS)
    if (nRetT > 0): PlotSubHistF11("RetT", aRetT, RetT0, dRetT, iRetT, nRetT)
    if (nRetR > 0): PlotSubHistF11("RetR", aRetR, RetR0, dRetR, iRetR, nRetR)
    if (nERaT > 0): PlotSubHistF11("ERaT", aERaT, ERaT0, dERaT, iERaT, nERaT)
    if (nERaR > 0): PlotSubHistF11("ERaR", aERaR, ERaR0, dERaR, iERaR, nERaR)
    if (nRotaT > 0): PlotSubHistF11("RotaT", aRotaT, RotaT0, dRotaT, iRotaT, nRotaT)
    if (nRotaR > 0): PlotSubHistF11("RotaR", aRotaR, RotaR0, dRotaR, iRotaR, nRotaR)
    if (nLDRCal > 0): PlotSubHistF11("LDRCal", aLDRCal, LDRCal0, dLDRCal, iLDRCal, nLDRCal)
    if (nTCalT > 0): PlotSubHistF11("TCalT", aTCalT, TCalT0, dTCalT, iTCalT, nTCalT)
    if (nTCalR > 0): PlotSubHistF11("TCalR", aTCalR, TCalR0, dTCalR, iTCalR, nTCalR)
    if (nNCal > 0): PlotSubHistF11("CalNoise", aNCal, 0, 1/nNCal, iNCal, nNCal)
    if (nNI > 0): PlotSubHistF11("SigNoise", aNI, 0, 1/nNI, iNI, nNI)


    plt.show()
    plt.close

    '''
    '''
    # only histogram
    #print("******************* " + aVar + " *******************")
    fig, ax = plt.subplots(nrows=5, ncols=2, sharex=True, sharey=True, figsize=(10, 10))
    iLDR = -1
    for LDRTrue in LDRrange:
        iLDR = iLDR + 1
        LDRmin[iLDR] = np.min(aLDRcorr[iLDR,:])
        LDRmax[iLDR] = np.max(aLDRcorr[iLDR,:])
        Rmin = np.min(aLDRcorr[iLDR,:])    * 0.999
        Rmax = np.max(aLDRcorr[iLDR,:])    * 1.001
        plt.subplot(5,2,iLDR+1)
        (n, bins, patches) = plt.hist(aLDRcorr[iLDR,:],
                 range=[Rmin, Rmax],
                 bins=200, log=False, alpha=0.2, density=False, color = '0.5', histtype='stepfilled')
        plt.tick_params(axis='both', labelsize=9)
        plt.plot([LDRTrue, LDRTrue], [0, np.max(n)], 'r-', lw=2)
    plt.show()
    plt.close
     # --- End of Plot F11 histograms
    '''

    # --- Plot LDRmin, LDRmax
    iLDR = -1
    for LDRTrue in LDRrange:
        iLDR = iLDR + 1
        LDRmin[iLDR] = np.amin(aLDRcorr[iLDR, :])
        LDRmax[iLDR] = np.amax(aLDRcorr[iLDR, :])

    fig2 = plt.figure()
    LDRrangeA = np.array(LDRrange)
    if((np.amax(LDRmax - LDRrangeA)-np.amin(LDRmin - LDRrangeA)) < 0.001):
        plt.ylim(-0.001,0.001)
    plt.plot(LDRrangeA, LDRmax - LDRrangeA, linewidth=2.0, color='b')
    plt.plot(LDRrangeA, LDRmin - LDRrangeA, linewidth=2.0, color='g')

    plt.xlabel('LDRtrue', fontsize=18)
    plt.ylabel('LDRTrue-LDRmin, LDRTrue-LDRmax', fontsize=14)
    plt.title(LID + ' ' + str(Type[TypeC]) + ' ' + str(Loc[LocC]), fontsize=18)
    # plt.ylimit(-0.07, 0.07)
    plt.show()
    plt.close

    # --- Save LDRmin, LDRmax to file
    # http://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python
    with open('output_files\\' + LID + '-' + InputFile[0:-3] + '-LDR_min_max.dat', 'w') as f:
        with redirect_stdout(f):
            print(LID)
            print("LDRtrue, LDRmin, LDRmax")
            for i in range(len(LDRrangeA)):
                print("{0:7.4f},{1:7.4f},{2:7.4f}".format(LDRrangeA[i], LDRmin[i], LDRmax[i]))


    if (bPlotEtax):
        if (nDOLP > 0): PlotEtax("DOLP", aDOLP, DOLP0, dDOLP, iDOLP, nDOLP)
        if (nRotL > 0): PlotEtax("RotL", aRotL, RotL0, dRotL, iRotL, nRotL)
        if (nRetE > 0): PlotEtax("RetE", aRetE, RetE0, dRetE, iRetE, nRetE)
        if (nRotE > 0): PlotEtax("RotE", aRotE, RotE0, dRotE, iRotE, nRotE)
        if (nDiE > 0): PlotEtax("DiE", aDiE, DiE0, dDiE, iDiE, nDiE)
        if (nRetO > 0): PlotEtax("RetO", aRetO, RetO0, dRetO, iRetO, nRetO)
        if (nRotO > 0): PlotEtax("RotO", aRotO, RotO0, dRotO, iRotO, nRotO)
        if (nDiO > 0): PlotEtax("DiO", aDiO, DiO0, dDiO, iDiO, nDiO)
        if (nDiC > 0): PlotEtax("DiC", aDiC, DiC0, dDiC, iDiC, nDiC)
        if (nRotC > 0): PlotEtax("RotC", aRotC, RotC0, dRotC, iRotC, nRotC)
        if (nRetC > 0): PlotEtax("RetC", aRetC, RetC0, dRetC, iRetC, nRetC)
        if (nTP > 0): PlotEtax("TP", aTP, TP0, dTP, iTP, nTP)
        if (nTS > 0): PlotEtax("TS", aTS, TS0, dTS, iTS, nTS)
        if (nRP > 0): PlotEtax("RP", aRP, RP0, dRP, iRP, nRP)
        if (nRS > 0): PlotEtax("RS", aRS, RS0, dRS, iRS, nRS)
        if (nRetT > 0): PlotEtax("RetT", aRetT, RetT0, dRetT, iRetT, nRetT)
        if (nRetR > 0): PlotEtax("RetR", aRetR, RetR0, dRetR, iRetR, nRetR)
        if (nERaT > 0): PlotEtax("ERaT", aERaT, ERaT0, dERaT, iERaT, nERaT)
        if (nERaR > 0): PlotEtax("ERaR", aERaR, ERaR0, dERaR, iERaR, nERaR)
        if (nRotaT > 0): PlotEtax("RotaT", aRotaT, RotaT0, dRotaT, iRotaT, nRotaT)
        if (nRotaR > 0): PlotEtax("RotaR", aRotaR, RotaR0, dRotaR, iRotaR, nRotaR)
        if (nLDRCal > 0): PlotEtax("LDRCal", aLDRCal, LDRCal0, dLDRCal, iLDRCal, nLDRCal)
        if (nTCalT > 0): PlotEtax("TCalT", aTCalT, TCalT0, dTCalT, iTCalT, nTCalT)
        if (nTCalR > 0): PlotEtax("TCalR", aTCalR, TCalR0, dTCalR, iTCalR, nTCalR)
        if (nNCal > 0): PlotEtax("CalNoiseTp", aNCalTp, 0, 1, iNCalTp, nNCal)
        if (nNCal > 0): PlotEtax("CalNoiseTm", aNCalTm, 0, 1, iNCalTm, nNCal)
        if (nNCal > 0): PlotEtax("CalNoiseRp", aNCalRp, 0, 1, iNCalRp, nNCal)
        if (nNCal > 0): PlotEtax("CalNoiseRm", aNCalRm, 0, 1, iNCalRm, nNCal)
        if (nNI > 0): PlotEtax("SigNoiseIt", aNIt, 0, 1, iNIt, nNI)
        if (nNI > 0): PlotEtax("SigNoiseIr", aNIr, 0, 1, iNIr, nNI)
        plt.show()
        plt.close
        
        #Etaxmin = np.amin(aEtax[1, :])
        Etaxmin = np.amin(aEtax[1, :])
        Etaxmax = np.amax(aEtax[1, :])
        Etaxstd = np.std(aEtax[1, :])
        Etaxmean = np.mean(aEtax[1, :])
        Etaxmedian = np.mean(aEtax[1, :])
        
        print("Etax: mean±std, median, max-mean, mean-min")
        print("{0:7.4f}±{1:7.4f},{2:7.4f},+{3:7.4f},-{4:7.4f}".format(Etaxmean, Etaxstd, Etaxmedian, Etaxmax-Etaxmean, Etaxmean-Etaxmin, ))
    
    '''
    # --- Plot K over LDRCal
    fig3 = plt.figure()
    plt.plot(LDRCal0+aLDRCal*dLDRCal/nLDRCal,aGHK[4,:], linewidth=2.0, color='b')

    plt.xlabel('LDRCal', fontsize=18)
    plt.ylabel('K', fontsize=14)
    plt.title(LID, fontsize=18)
    plt.show()
    plt.close
    '''

# Additional plot routines ======>
'''
#******************************************************************************
# 1. Plot LDRcorrected - LDR(measured Icross/Iparallel)
LDRa = np.arange(1.,100.)*0.005
LDRCorra = np.arange(1.,100.)
if Y == - 1.: LDRa = 1./LDRa
LDRCorra = (1./Eta*LDRa*(GT+HT)-(GR+HR))/((GR-HR)-1./Eta*LDRa*(GT-HT))
if Y == - 1.: LDRa = 1./LDRa
#
#fig = plt.figure()
plt.plot(LDRa,LDRCorra-LDRa)
plt.plot([0.,0.5],[0.,0.5])
plt.suptitle('LDRcorrected - LDR(measured Icross/Iparallel)', fontsize=16)
plt.xlabel('LDR', fontsize=18)
plt.ylabel('LDRCorr - LDR', fontsize=16)
#plt.savefig('test.png')
#
'''
'''
#******************************************************************************
# 2. Plot LDRsim (simulated measurements without corrections = Icross/Iparallel) over LDRtrue
LDRa = np.arange(1.,100.)*0.005
LDRsima = np.arange(1.,100.)

atruea = (1.-LDRa)/(1+LDRa)
Ita = TiT*TiO*IinL*(GT+atruea*HT)
Ira = TiR*TiO*IinL*(GR+atruea*HR)
LDRsima = Ira/Ita  # simulated uncorrected LDR with Y from input file
if Y == -1.: LDRsima = 1./LDRsima
#
#fig = plt.figure()
plt.plot(LDRa,LDRsima)
plt.plot([0.,0.5],[0.,0.5])
plt.suptitle('LDRsim (simulated measurements without corrections = Icross/Iparallel) over LDRtrue', fontsize=10)
plt.xlabel('LDRtrue', fontsize=18)
plt.ylabel('LDRsim', fontsize=16)
#plt.savefig('test.png')
#
'''

mercurial