diff --git a/Makefile b/Makefile index 5c04e1d7..ebfc4a7e 100644 --- a/Makefile +++ b/Makefile @@ -18,8 +18,8 @@ fftw_dir = $(fftw_version) fftw_file = $(fftw_version).tar.gz log_fftw = /dev/null examples_dir = $(env_dir)/work/srw_python -example10_data_dir = $(examples_dir)/data_example_10 -timeout=20 +#example10_data_dir = $(examples_dir)/data_example_10 +export MODE ?= 0 nofftw: core pylib diff --git a/README.txt b/README.txt index 97a58aba..aefae72e 100644 --- a/README.txt +++ b/README.txt @@ -7,7 +7,7 @@ SRW is a physical optics computer code for calculation of detailed characteristi In the following writing, it is assumed that "SRW_Dev" is absolute path to the full SRW directory (obtained e.g. after downloading from repository). -Using pre-compiled SRW libraries and clients / bindings: +I. Using pre-compiled SRW libraries and clients / bindings: -------------------------------------------------------- The last ~"clean" release of SRW for IGOR Pro and for Python can be found in SRW_Dev/env/release, in particular: - installers (of compressed packages) can be found in SRW_Dev/env/release/install; @@ -15,44 +15,51 @@ The last ~"clean" release of SRW for IGOR Pro and for Python can be found in SRW SRW_Dev/env/release/srw_igor; this folder contains ReadMe.txt file with general "start-up" notes; detailed documentation for IGOR Pro version can be found in: SRW_Dev/env/release/srw_igor/SRW Help/SRW Help.ifn file (in IGOR formatted notebook format); - unpacked folder of SRW for Python (for Windows and Linux) is: SRW_Dev/env/release/srw_python; this folder contains ReadMe.txt file with general "start-up" notes. -Besides, some recent pre-releases and current work versions of SRW for Python and for IGOR Pro can be found in: SRW_Dev/env/work. +The most recent pre-releases and current work versions of SRW for Python and for IGOR Pro can be found in: SRW_Dev/env/work. -Testing of the pre-compiled SRW libraries and clients / bindings can be done using examples included both to Python and IGOR Pro versions of SRW (see "Check example" section below for a particular platform). +Testing of the pre-compiled SRW libraries and clients / bindings can be done using examples included both to Python and IGOR Pro versions of SRW (see "Checking the examples" sections below for different platforms). -I. Compiling and testing SRW Library and its Python and IGOR Pro bindings on Windows: +II. Compiling and testing SRW Library and its Python and IGOR Pro bindings on Windows. ------------------------------------------------------------------ -1. Compile SRWLib library and Python binding using MS Visual Studio: - Microsoft Visual C++ 2015 (or later version) solution file (SRW.sln), which includes 4 projects: +II.1. Compiling SRW library and Python binding using MS Visual C++. + +II.1.1. Microsoft Visual C++ 2015 (or later version) solution file (SRW.sln), which includes 4 projects: - SRW Library (file SRWLIB.vcxproj), - SRW Python client / binding (file SRWLClientPython.vcxproj), - SRW IGOR Pro client / binding (file SRWLClientIgor.vcxproj), - SRW C demo client (file SRWLClientC.vcxproj), -can be found in SRW_Dev/cpp/vc. These project files allow for compiling SRW for Python 2.7 and 3.x (64-bit or 32-bit), and SRW for IGOR Pro (32-bit only). Free Microsoft Visual Studio Community 2015 (or later versions) can be used. +can be found in SRW_Dev/cpp/vc. The SRWLClientPython project file allows for compiling "srwlpy.pyd" shared library, i.e. SRW for Python 2.7 or/and 3.x (64-bit or 32-bit); SRWLClientIgor allows for compiling "SRW.xop" shared library, i.e. SRW for IGOR Pro (32-bit only). Free Microsoft Visual Studio Community 2015 (or later versions) can be used. + To compile SRW library supporting OpenMP based parallel calculations (e.g. for XFEL applications): + - In the Visual C++ Configuration Manager, select "ReleaseOMP" version of the SRWLIB project, then re-compile SRWLIB and SRWLClientPython under the "x64" Solution Platform to produce a 64-bit version of SRW for Python supporting OpenMP based parallel calculations. + - Note that the "ReleaseOMP" version of the SRWLIB project has only two differences with respect to the standard version: the "_WITH_OMP" preprocessor definition is added to Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, and the "Open MP Support" option is set to "Yes (/openmp)" in Configuration Properties -> C/C++ -> Language -> Open MP Support. -2. Check examples: +II.2. Checking the examples. -2.1. The SRW for Python examples can be tested using e.g. "IDLE" (Python native GUI). To do so, start this application (e.g. from Windows Start menu), open an example file in it, e.g. "SRW_Dev\env\work\srw_python\SRWLIB_Example01.py", and run it from the IDLE. +II.2.1. The SRW for Python examples can be tested using e.g. "IDLE" (Python native GUI). To do so, start this application (e.g. from Windows Start menu), open an example file in it, e.g. "SRW_Dev\env\work\srw_python\SRWLIB_Example01.py", and run it from the IDLE. Alternatively, the example scripts can be executed from the Windows Command Prompt, e.g. from within the "SRW_Dev\env\work\srw_python" directory. For convenience, correct path to python.exe file may need to be specified in the Windows system PATH variable prior to these tests. -2.2. The The SRW for IGOR Pro examples can be tested from "SRWE" and "SRWP" menus, "Help" sub-menus, of the IGOR Pro. +II.2.2. The SRW for IGOR Pro examples can be tested from "SRWE" and "SRWP" menus, "Help" sub-menus, of the IGOR Pro. -II. Compiling and testing SRW Library and its Python binding on Linux: +III. Compiling and testing SRW Library and its Python binding on Linux. ------------------------------------------------------------------ -1. Compile SRWLib library and Python binding: - This can be done either using Python "distutils" (see section 2.1 below) or without it (see section 2.2) +III.1. Compiling SRW library and Python binding. + This can be done either using Python "distutils" (see section II.1.1 below) or without it (see section II.1.2). -1.1. Compiling using Python "distutils" module: +III.1.1. Compiling using Python "distutils" module. Make sure the "distutils" module of the Python version you would like to use is properly installed and configured. If this is done, the compilation and installation is simple: cd SRW_Dev make all + To compile SRW library supporting OpenMP based parallel calculations (e.g. for XFEL applications) use add "MODE=omp" after "make all": + make all MODE=omp This should compile libsrw.a and srwlpy.so, and copy srwlpy.so to SRW_Dev/env/work/srw_python/ -1.2. Compiling without "distutils": -1.2.1. Download and compile fftw-2.1.5 library as required for SRW: - Download fftw-2.1.5.tar.gz from FFTW site (probably http://www.fftw.org/download.html) and place it to SRW_Dev/ext_lib +III.1.2. Compiling without "distutils". + +III.1.2.1. Download and compile fftw-2.1.5 library as required for SRW. + Download fftw-2.1.5.tar.gz from FFTW site (probably http://www.fftw.org/download.html) and place it to SRW_Dev/ext_lib: cd SRW_Dev/ext_lib tar -zxvf fftw-2.1.5.tar.gz cd fftw-2.1.5 @@ -62,30 +69,60 @@ II. Compiling and testing SRW Library and its Python binding on Linux: make install cp fftw/.libs/libfftw.a SRW_Dev/ext_lib/ -1.2.2. Compile the SRW library and Python binding: +III.1.2.2. Compile the SRW library and Python binding. cd SRW_Dev/cpp/gcc - Make sure that Python 3.2 or higher (or Python 2.7) is installed - In Makefile, modify/correct PYPATH and PYFLAGS variables, i.e. specify path to Python header and library files + Make sure Python 3.2 or higher (or Python 2.7) is installed. + In the SRW_Dev/cpp/gcc/Makefile, modify/correct PYPATH and PYFLAGS variables, i.e. specify path to Python header and library files. Depending on Linux environment, it may also be necessary to modify the name of compiler to be used, e.g.: + CC = gcc + CXX = g++ + #CC = cc + #CXX = c++ + After this, execute the following: rm libsrw.a make all + To compile SRW library supporting OpenMP based parallel calculations (e.g. for XFEL applications) use add "MODE=omp" after "make all": + make all MODE=omp + Then copy srwlpy.so to SRW_Dev/env/work/srw_python/: cp srwlpy.so ../../env/work/srw_python/ -2. Check examples: - Make sure the path to Python 3.5 (or 2.7) is added to the PATH variable and "srw_python" to PYTHONPATH variable: - export PATH="$PATH:" # this is not necessary if you install python using the distro's package manager - export PYTHONPAH="$PYTHONPATH:SRW_Dev/env/work/srw_python/" # temporarely solution +III.2. Checking the examples. + Make sure the path to Python 3.x (or 2.7) is added to the PATH variable and "srw_python" to PYTHONPATH variable: + export PATH="$PATH:" # this is not necessary if you install python using the distro's package manager + export PYTHONPAH="$PYTHONPATH:SRW_Dev/env/work/srw_python/" #temporary solution or - echo "export PYTHONPATH=$PYTHONPATH:SRW_Dev/env/work/srw_python/" >> ~/.bashrc # permanent solution for a single user - Setting up PYTHONPATH allows to import srwlpy module from any directory. + echo "export PYTHONPATH=$PYTHONPATH:SRW_Dev/env/work/srw_python/" >> ~/.bashrc #permanent solution for a single user + Setting up PYTHONPATH allows to import srwlpy module from any directory. Testing of the examples would preferably done in the "srw_python" directory: cd SRW_Dev/env/work/srw_python python SRWLIB_ExampleXX.py +IV. Compiling and testing SRW Library and its Python binding on Mac OSX. +------------------------------------------------------------------ + Try to follow the steps described in section III, describing options for compiling and testing SRW on Linux. + We were informed that the actions described in III.1.2.2 lead to successful compilation with gcc/g++ provided by Xcode 10.1, after the following modifications in SRW_Dev/cpp/gcc/Makefile: + CC = gcc + CXX = g++ + #CC = cc + #CXX = c++ + ... + PYPATH=/Library/Frameworks/Python.framework/Versions/3.6 + PYFLAGS=-I$(PYPATH)/include/python3.6m -I$(PYPATH)/include/python3.6m -L$(PYPATH)/lib/python3.6/config-3.6m-darwin -lpython3.6m -ldl + + The correct path and flags can be obtained e.g. by executing from command line: + python3-config --includes --ldflags + and removing the option -framework + + With earlier versions of Xcode, the following manipulations, consisting in installation of "macports" and obtaining the whole gcc toolchain, were reported to be successful: + sudo port install gcc47 + Modify the SRW_Dev/cpp/gcc/Makefile so that CC=/gcc and CXX=/g++, and proceed to the compilation as described in III.1.2.2. + + Authors and Contributors to SRW project: ---------------------------------------- O. Chubar (ESRF - SOLEIL - BNL) P. Elleaume (ESRF) J. Chavanne (ESRF) +R. Celestre (ESRF) P. Dumas (SOLEIL) O. Marcouille (SOLEIL) L. Samoylova (E-XFEL) @@ -94,12 +131,14 @@ G. Geloni (E-XFEL) I. Agapov (E-XFEL) J. Sutter (DIAMOND) D. Laundy (DIAMOND) +A. He (BNL) M. Rakitin (BNL) N. Canestrari (ESRF - BNL) A. Suvorov (BNL) R. Reininger (ANL) X. Shi (ANL) R. Lindberg (ANL) +L. Rebuffi (ELETTRA - ANL) D. Bruhwiler (RadiaSoft LLC) R. Nagler (RadiaSoft LLC) P. Moeller (Bivio Inc) diff --git a/cpp/gcc/MAC_COMPILE.txt b/cpp/gcc/MAC_COMPILE.txt deleted file mode 100644 index 387bd7da..00000000 --- a/cpp/gcc/MAC_COMPILE.txt +++ /dev/null @@ -1,5 +0,0 @@ -on Mac install macports and get the whole gcc toolchain: -sudo port install gcc47 -modify the Makefile so that CC=/path/to/macports/gcc -and CXX=/path/to/macports/g++ - diff --git a/cpp/gcc/client_srwlib_makefile02.linux.old b/cpp/gcc/client_srwlib_makefile02.linux.old deleted file mode 100644 index f82de9a4..00000000 --- a/cpp/gcc/client_srwlib_makefile02.linux.old +++ /dev/null @@ -1,32 +0,0 @@ - - -SOFT_DEV_DIR= /cygdrive/c/SoftwareDevelopments -SRW_SRC_DIR= $(SOFT_DEV_DIR)/SRW_Dev/source -SRW_SRC_GEN_DIR= $(SRW_SRC_DIR)/general -SRW_SRC_DLL_DIR= $(SRW_SRC_DIR)/dll -SRW_SRC_GENESIS_DIR= $(SRW_SRC_DIR)/genesis_july08 -SRW_SRC_CLC= $(SRW_SRC_DIR)/client_c -SRW_CLC_EXE= $(SOFT_DEV_DIR)/SRW_Dev/clients/srwlib_c -SH_DIR= $(SOFT_DEV_DIR)/Shared -SH_SRC_DIR= $(SH_DIR)/source -SH_SRC_PARSE_DIR= $(SH_SRC_DIR)/auxparse -SH_SRC_GEN_MATH_DIR= $(SH_SRC_DIR)/genmath -SH_LIB_DIR= $(SH_DIR)/lib - -CFL= -OPT= -O3 -SRW_SRC_DEF= -D__GCC__ -DFFTW_ENABLE_FLOAT -D_GM_WITHOUT_BASE -DSRWLIB_STATIC -DNO_TIMER -DANSI_DECLARATORS -DTRILIBRARY -DLINUX -LIB= -L$(SH_LIB_DIR) -lsrw -lfftw -LIBSRW= -lsrw - -OBJ= srwlclient.o - -PRG= srwlclient.exe - -pgm: $(OBJ) - g++ $(OBJ) $(LIB) -o $(PRG) - cp $(PRG) $(SRW_CLC_EXE)/ - -srwlclient.o: $(SRW_SRC_CLC)/srwlclient.cpp - g++ $(CFL) -c $(SRW_SRC_CLC)/srwlclient.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - diff --git a/cpp/gcc/srwlib_makefile03.linux.old b/cpp/gcc/srwlib_makefile03.linux.old deleted file mode 100644 index 3ad47a64..00000000 --- a/cpp/gcc/srwlib_makefile03.linux.old +++ /dev/null @@ -1,274 +0,0 @@ - - -SOFT_DEV_DIR= /cygdrive/c/SoftwareDevelopments -SRW_SRC_DIR= $(SOFT_DEV_DIR)/SRW_Dev/source -SRW_SRC_GEN_DIR= $(SRW_SRC_DIR)/general -SRW_SRC_DLL_DIR= $(SRW_SRC_DIR)/dll -SRW_SRC_GENESIS_DIR= $(SRW_SRC_DIR)/genesis_july08 -SH_DIR= $(SOFT_DEV_DIR)/Shared -SH_SRC_DIR= $(SH_DIR)/source -SH_SRC_PARSE_DIR= $(SH_SRC_DIR)/auxparse -SH_SRC_GEN_MATH_DIR= $(SH_SRC_DIR)/genmath -SH_LIB_DIR= $(SH_DIR)/lib - -CFL= -OPT= -O3 -SRW_SRC_DEF= -D__GCC__ -DFFTW_ENABLE_FLOAT -D_GM_WITHOUT_BASE -DSRWLIB_STATIC -DNO_TIMER -DANSI_DECLARATORS -DTRILIBRARY -DLINUX -LIB= -L$(SH_LIB_DIR) -lfftw -lm -lpthread -lrt - -OBJ= srwlib.o srerror.o auxparse.o gminterp.o gmmeth.o gmtrans.o srappl.o srclcuti.o srcradint.o srctrjdt.o sremitpr.o srfft.o srfit.o srgsnbm.o srgtrjdt.o srisosrc.o srmagcnt.o srmagfld.o srmamet.o srmatsta.o sroptapt.o sroptcnt.o sroptdrf.o sroptel2.o sroptel3.o sroptelm.o sroptfoc.o sroptgrat.o sroptgtr.o sropthck.o sroptics.o sroptmat.o sroptpsh.o sroptshp.o sroptsmr.o sroptwgr.o sroptzp.o sroptzps.o srpersto.o srpowden.o srprdint.o srprgind.o srpropme.o srptrjdt.o srradinc.o srradint.o srradmnp.o srradstr.o srremflp.o srsase.o srsend.o srstowig.o srsysuti.o srthckbm.o srthckbm2.o srtrjaux.o srtrjdat.o srtrjdat3d.o all_com.o check.o diagno.o esource.o field.o incoherent.o initrun.o input.o loadbeam.o loadrad.o magfield.o main.o math.o mpi.o output.o partsim.o pushp.o rpos.o scan.o source.o stepz.o string.o tdepend.o timerec.o track.o - -PRG= libsrw.a - -pgm: $(OBJ) - ar -cvq $(PRG) $(OBJ) - cp $(PRG) $(SH_LIB_DIR)/ - -srwlib.o: $(SRW_SRC_DLL_DIR)/srwlib.cpp - cc $(CFL) -c $(SRW_SRC_DLL_DIR)/srwlib.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srerror.o: $(SRW_SRC_DLL_DIR)/srerror.cpp - cc $(CFL) -c $(SRW_SRC_DLL_DIR)/srerror.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SH_SRC_PARSE_DIR) - -auxparse.o: $(SH_SRC_PARSE_DIR)/auxparse.cpp - cc $(CFL) -c $(SH_SRC_PARSE_DIR)/auxparse.cpp $(OPT) $(SRW_SRC_DEF) - -gminterp.o: $(SH_SRC_GEN_MATH_DIR)/gminterp.cpp - cc $(CFL) -c $(SH_SRC_GEN_MATH_DIR)/gminterp.cpp $(OPT) $(SRW_SRC_DEF) - -gmmeth.o: $(SH_SRC_GEN_MATH_DIR)/gmmeth.cpp - cc $(CFL) -c $(SH_SRC_GEN_MATH_DIR)/gmmeth.cpp $(OPT) $(SRW_SRC_DEF) - -gmtrans.o: $(SH_SRC_GEN_MATH_DIR)/gmtrans.cpp - cc $(CFL) -c $(SH_SRC_GEN_MATH_DIR)/gmtrans.cpp $(OPT) $(SRW_SRC_DEF) - -srappl.o: $(SRW_SRC_GEN_DIR)/srappl.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srappl.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srclcuti.o: $(SRW_SRC_GEN_DIR)/srclcuti.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srclcuti.cpp $(OPT) $(SRW_SRC_DEF) - -srcradint.o: $(SRW_SRC_GEN_DIR)/srcradint.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srcradint.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srctrjdt.o: $(SRW_SRC_GEN_DIR)/srctrjdt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srctrjdt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sremitpr.o: $(SRW_SRC_GEN_DIR)/sremitpr.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sremitpr.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srfft.o: $(SRW_SRC_GEN_DIR)/srfft.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srfft.cpp $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -srfit.o: $(SRW_SRC_GEN_DIR)/srfit.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srfit.cpp $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -srgsnbm.o: $(SRW_SRC_GEN_DIR)/srgsnbm.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srgsnbm.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srgtrjdt.o: $(SRW_SRC_GEN_DIR)/srgtrjdt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srgtrjdt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srisosrc.o: $(SRW_SRC_GEN_DIR)/srisosrc.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srisosrc.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srmagcnt.o: $(SRW_SRC_GEN_DIR)/srmagcnt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srmagcnt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srmagfld.o: $(SRW_SRC_GEN_DIR)/srmagfld.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srmagfld.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srmamet.o: $(SRW_SRC_GEN_DIR)/srmamet.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srmamet.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srmatsta.o: $(SRW_SRC_GEN_DIR)/srmatsta.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srmatsta.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptapt.o: $(SRW_SRC_GEN_DIR)/sroptapt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptapt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptcnt.o: $(SRW_SRC_GEN_DIR)/sroptcnt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptcnt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptdrf.o: $(SRW_SRC_GEN_DIR)/sroptdrf.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptdrf.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptel2.o: $(SRW_SRC_GEN_DIR)/sroptel2.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptel2.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptel3.o: $(SRW_SRC_GEN_DIR)/sroptel3.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptel3.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptelm.o: $(SRW_SRC_GEN_DIR)/sroptelm.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptelm.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptfoc.o: $(SRW_SRC_GEN_DIR)/sroptfoc.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptfoc.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptgrat.o: $(SRW_SRC_GEN_DIR)/sroptgrat.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptgrat.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptgtr.o: $(SRW_SRC_GEN_DIR)/sroptgtr.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptgtr.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sropthck.o: $(SRW_SRC_GEN_DIR)/sropthck.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sropthck.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptics.o: $(SRW_SRC_GEN_DIR)/sroptics.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptics.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptmat.o: $(SRW_SRC_GEN_DIR)/sroptmat.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptmat.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptpsh.o: $(SRW_SRC_GEN_DIR)/sroptpsh.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptpsh.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptshp.o: $(SRW_SRC_GEN_DIR)/sroptshp.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptshp.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptsmr.o: $(SRW_SRC_GEN_DIR)/sroptsmr.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptsmr.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptwgr.o: $(SRW_SRC_GEN_DIR)/sroptwgr.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptwgr.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptzp.o: $(SRW_SRC_GEN_DIR)/sroptzp.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptzp.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -sroptzps.o: $(SRW_SRC_GEN_DIR)/sroptzps.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/sroptzps.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srpersto.o: $(SRW_SRC_GEN_DIR)/srpersto.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srpersto.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srpowden.o: $(SRW_SRC_GEN_DIR)/srpowden.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srpowden.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srprdint.o: $(SRW_SRC_GEN_DIR)/srprdint.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srprdint.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srprgind.o: $(SRW_SRC_GEN_DIR)/srprgind.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srprgind.cpp $(OPT) $(SRW_SRC_DEF) - -srpropme.o: $(SRW_SRC_GEN_DIR)/srpropme.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srpropme.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srptrjdt.o: $(SRW_SRC_GEN_DIR)/srptrjdt.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srptrjdt.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srradinc.o: $(SRW_SRC_GEN_DIR)/srradinc.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srradinc.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srradint.o: $(SRW_SRC_GEN_DIR)/srradint.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srradint.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srradmnp.o: $(SRW_SRC_GEN_DIR)/srradmnp.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srradmnp.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srradstr.o: $(SRW_SRC_GEN_DIR)/srradstr.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srradstr.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srremflp.o: $(SRW_SRC_GEN_DIR)/srremflp.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srremflp.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srsase.o: $(SRW_SRC_GEN_DIR)/srsase.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srsase.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srsend.o: $(SRW_SRC_GEN_DIR)/srsend.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srsend.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srstowig.o: $(SRW_SRC_GEN_DIR)/srstowig.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srstowig.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srsysuti.o: $(SRW_SRC_GEN_DIR)/srsysuti.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srsysuti.cpp $(OPT) $(SRW_SRC_DEF) - -srthckbm.o: $(SRW_SRC_GEN_DIR)/srthckbm.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srthckbm.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srthckbm2.o: $(SRW_SRC_GEN_DIR)/srthckbm2.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srthckbm2.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_GEN_DIR) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srtrjaux.o: $(SRW_SRC_GEN_DIR)/srtrjaux.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srtrjaux.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srtrjdat.o: $(SRW_SRC_GEN_DIR)/srtrjdat.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srtrjdat.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -srtrjdat3d.o: $(SRW_SRC_GEN_DIR)/srtrjdat3d.cpp - cc $(CFL) -c $(SRW_SRC_GEN_DIR)/srtrjdat3d.cpp $(OPT) $(SRW_SRC_DEF) -I$(SRW_SRC_DLL_DIR) -I$(SH_SRC_PARSE_DIR) -I$(SH_SRC_GEN_MATH_DIR) - -all_com.o: $(SRW_SRC_GENESIS_DIR)/all_com.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/all_com.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -check.o: $(SRW_SRC_GENESIS_DIR)/check.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/check.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -diagno.o: $(SRW_SRC_GENESIS_DIR)/diagno.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/diagno.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -esource.o: $(SRW_SRC_GENESIS_DIR)/esource.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/esource.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -field.o: $(SRW_SRC_GENESIS_DIR)/field.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/field.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -incoherent.o: $(SRW_SRC_GENESIS_DIR)/incoherent.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/incoherent.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -initrun.o: $(SRW_SRC_GENESIS_DIR)/initrun.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/initrun.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -input.o: $(SRW_SRC_GENESIS_DIR)/input.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/input.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -loadbeam.o: $(SRW_SRC_GENESIS_DIR)/loadbeam.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/loadbeam.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -loadrad.o: $(SRW_SRC_GENESIS_DIR)/loadrad.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/loadrad.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -magfield.o: $(SRW_SRC_GENESIS_DIR)/magfield.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/magfield.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -main.o: $(SRW_SRC_GENESIS_DIR)/main.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/main.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -math.o: $(SRW_SRC_GENESIS_DIR)/math.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/math.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -mpi.o: $(SRW_SRC_GENESIS_DIR)/mpi.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/mpi.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -output.o: $(SRW_SRC_GENESIS_DIR)/output.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/output.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -partsim.o: $(SRW_SRC_GENESIS_DIR)/partsim.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/partsim.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -pushp.o: $(SRW_SRC_GENESIS_DIR)/pushp.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/pushp.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -rpos.o: $(SRW_SRC_GENESIS_DIR)/rpos.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/rpos.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -scan.o: $(SRW_SRC_GENESIS_DIR)/scan.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/scan.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -source.o: $(SRW_SRC_GENESIS_DIR)/source.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/source.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -stepz.o: $(SRW_SRC_GENESIS_DIR)/stepz.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/stepz.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -string.o: $(SRW_SRC_GENESIS_DIR)/string.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/string.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -tdepend.o: $(SRW_SRC_GENESIS_DIR)/tdepend.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/tdepend.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -timerec.o: $(SRW_SRC_GENESIS_DIR)/timerec.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/timerec.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) - -track.o: $(SRW_SRC_GENESIS_DIR)/track.c - cc $(CFL) -c $(SRW_SRC_GENESIS_DIR)/track.c $(OPT) $(SRW_SRC_DEF) -I$(SH_SRC_GEN_MATH_DIR) diff --git a/cpp/py/Makefile b/cpp/py/Makefile index fbe070f7..8fea6432 100644 --- a/cpp/py/Makefile +++ b/cpp/py/Makefile @@ -1,9 +1,11 @@ .PHONY: python clean +MODE ?= 0 + python: srwlpy.so srwlpy.so: - python setup.py build_ext --build-lib='../gcc' + MODE=$(MODE) python setup.py build_ext --build-lib='../gcc' cp ../gcc/srwlpy*.so ../../env/work/srw_python/ rm -rf build diff --git a/cpp/py/setup.py b/cpp/py/setup.py index e4237179..341b8f93 100644 --- a/cpp/py/setup.py +++ b/cpp/py/setup.py @@ -1,13 +1,32 @@ -from distutils.core import setup, Extension +#from distutils.core import setup, Extension +from setuptools import setup, Extension import os -srwlpy = Extension( - 'srwlpy', - define_macros=[('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], - include_dirs=[os.path.abspath('../src/lib')], - libraries=['srw', 'm', 'fftw'], - library_dirs=[os.path.abspath('../gcc'), os.path.abspath('../../ext_lib')], - sources=[os.path.abspath('../src/clients/python/srwlpy.cpp')]) +#srwlpy = Extension( +# 'srwlpy', +# extra_link_args=['-fopenmp'], +# extra_compile_args=['-Wno-sign-compare','-Wno-parentheses','-fopenmp','-Wno-write-strings'], +# define_macros=[('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], +# include_dirs=[os.path.abspath('../src/lib')], +# libraries=['srw', 'm', 'fftw'], +# library_dirs=[os.path.abspath('../gcc'), os.path.abspath('../../ext_lib')], +# sources=[os.path.abspath('../src/clients/python/srwlpy.cpp')]) + +ext_kwargs = {'define_macros': [('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], + 'include_dirs': [os.path.abspath('../src/lib')], + 'libraries': ['srw', 'm', 'fftw'], + 'library_dirs': [os.path.abspath('../gcc'), os.path.abspath('../../ext_lib')], + 'sources': [os.path.abspath('../src/clients/python/srwlpy.cpp')]} + +if 'MODE' in os.environ: + sMode = str(os.environ['MODE']) + if sMode == 'omp': + ext_kwargs.update({'extra_link_args': ['-fopenmp'], + 'extra_compile_args': ['-Wno-sign-compare','-Wno-parentheses','-fopenmp','-Wno-write-strings']}) + elif sMode != '0': + raise Exception("Unknown SRW compilation/linking option") + +srwlpy = Extension('srwlpy', **ext_kwargs) setup(name='SRW Python interface', version='1.0', diff --git a/cpp/src/clients/igor/srigintw.rc b/cpp/src/clients/igor/srigintw.rc index 69c5234e..a7015e86 100644 --- a/cpp/src/clients/igor/srigintw.rc +++ b/cpp/src/clients/igor/srigintw.rc @@ -222,6 +222,10 @@ BEGIN "Incorrect or insufficient parameters for spherical wave electric field calculation.\0", //#186 "Failed to determine array element index for interpolation.\0", //#187 + "Failed to allocate array in front-end / client environment.\0", //#188 + "Mutual intensity can not be extracted for these input parameters.\0", //189 + "Incorrect input parameters for calculation of statistical characteristics of intensity.\0", //190 + "Incorrect input parameters for processing intensity distributions.\0", //191 "\0" // NOTE: NULL required to terminate the resource. END diff --git a/cpp/src/clients/python/srwlpy.cpp b/cpp/src/clients/python/srwlpy.cpp index af5dd1f4..1284fb03 100644 --- a/cpp/src/clients/python/srwlpy.cpp +++ b/cpp/src/clients/python/srwlpy.cpp @@ -24,6 +24,10 @@ #include #include #include //OCTEST_161214 + +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +//#include + using namespace std; //Without the following Python.h will enforce usage of python**_d.lib in dbug mode, which may not be always existing @@ -73,7 +77,11 @@ static const char strEr_BadOptG[] = "Incorrect Optical Grating structure"; static const char strEr_BadOptT[] = "Incorrect Optical Generic Transmission structure"; static const char strEr_BadOptMir[] = "Incorrect Optical Mirror structure"; static const char strEr_BadOptCryst[] = "Incorrect Optical Crystal structure"; +static const char strEr_BadListIntProp[] = "Incorrect list structure defining intensity distributions to be plotted after propagation"; static const char strEr_FloatArrayRequired[] = "This function can be executed for float array(s) only"; +static const char strEr_FailedAllocPyArray[] = "Failed to allocate Python array from C"; +static const char strEr_FailedUpdateInt[] = "Failed to update intensity data after propagation"; +static const char strEr_FailedCreateList[] = "Failed to create resulting data list"; static const char strEr_BadArg_CalcMagnField[] = "Incorrect arguments for magnetic field calculation/tabulation function"; static const char strEr_BadArg_CalcPartTraj[] = "Incorrect arguments for trajectory calculation function"; @@ -92,6 +100,8 @@ static const char strEr_BadArg_UtiFFT[] = "Incorrect arguments for FFT function" static const char strEr_BadArg_UtiConvWithGaussian[] = "Incorrect arguments for convolution function"; static const char strEr_BadArg_UtiUndFromMagFldTab[] = "Incorrect arguments for magnetic field conversion to periodic function"; static const char strEr_BadArg_UtiUndFindMagFldInterpInds[] = "Incorrect arguments for magnetic field interpolaton index search function"; +static const char strEr_BadArg_UtiIntInf[] = "Incorrect arguments for function analyzing intensity distributions"; +static const char strEr_BadArg_UtiIntProc[] = "Incorrect arguments for function performing misc. operations on intensity distributions"; /************************************************************************//** * Global objects to be used across different function calls @@ -104,6 +114,7 @@ struct AuxStructPyObjectPtrs { }; static map gmWfrPyPtr; +static map gmBufPyObjPtr; //OC16082018 (was added to enable allocation of intensity arrays in Py at propagation) /************************************************************************//** * Auxiliary function dedicated to process errors reported by Library @@ -371,6 +382,50 @@ PyObject* Py_BuildValueChar(char inC) #endif } +/************************************************************************//** + * Sets up output list (eventually of lists) data from an array + ***************************************************************************/ +template static PyObject* SetPyListOfLists(T* arB, int nB, int nP, char* cType="d") //OC13092018 +{ + if((arB == 0) || (nB <= 0) || (nP <= 0)) return 0; + + int nElem = 0, nSubElem = 0; + if(nP == 1) + { + nElem = nB; + } + else + { + nElem = nP; + nSubElem = (int)round(nB/nP); + } + + PyObject *oResB = PyList_New(nElem); + T *t_arB = arB; //OC13092018 + //double *t_arB = arB; + for(int i=0; i 1) + { + oElem = PyList_New(nSubElem); + for(int j=0; j* pvBuf void ParseSructSRWLOptMir(SRWLOptMir* pOpt, PyObject* oOpt, vector* pvBuf) //throw(...) { if((pOpt == 0) || (oOpt == 0)) throw strEr_NoObj; - + + //PyObject *o_tmp = PyObject_GetAttrString(oOpt, "arRefl"); + //pOpt->arRefl = (double*)GetPyArrayBuf(o_tmp, pvBuf, 0); + //if(pOpt->arRefl == 0) throw strEr_BadOptMir; + //Py_DECREF(o_tmp); + + //OC12082018 + pOpt->arRefl = 0; //To allow not to process reflectivity if it is not defined PyObject *o_tmp = PyObject_GetAttrString(oOpt, "arRefl"); - pOpt->arRefl = (double*)GetPyArrayBuf(o_tmp, pvBuf, 0); - if(pOpt->arRefl == 0) throw strEr_BadOptMir; - Py_DECREF(o_tmp); + if(o_tmp != 0) + { + pOpt->arRefl = (double*)GetPyArrayBuf(o_tmp, pvBuf, 0); + Py_DECREF(o_tmp); + } o_tmp = PyObject_GetAttrString(oOpt, "reflNumPhEn"); if(o_tmp == 0) throw strEr_BadOptMir; @@ -2455,6 +2519,137 @@ void ParseSructSRWLOptC(SRWLOptC* pOpt, PyObject* oOpt, vector* pvBuf Py_DECREF(o_List); } +/************************************************************************//** + * Parses PyObject* to auxiliary arrays defining after which opt. elements + * and what type of intensity distributions have to be calculated. + * ATTENTION: it allocates arrays. + ***************************************************************************/ +int ParseSructSRWLPropIntDef(char** arIntDescr, SRWLRadMesh*& arIntMesh, PyObject* oInt) +{ + if(oInt == 0) throw strEr_NoObj; + + const int numIntDescr = 5; + + if(!PyList_Check(oInt)) throw strEr_BadList; + int nElem = (int)PyList_Size(oInt); + if(nElem <= 0) throw strEr_BadListIntProp; + + PyObject *o = PyList_GetItem(oInt, (Py_ssize_t)0); + if(o == 0) throw strEr_BadListIntProp; + + PyObject *oSub = 0; //, *oSubListPrev = 0; + bool assumeFlatListFormat = false; + + int nInt = 1; + bool elemsMeanLists = false; + if(PyList_Check(o)) + { + nInt = (int)PyList_Size(o); + if(nInt < 0) throw strEr_BadListIntProp; + + if(nInt == (numIntDescr + 1)) + { + oSub = PyList_GetItem(o, (Py_ssize_t)numIntDescr); + if(strcmp(oSub->ob_type->tp_name, "SRWLRadMesh") == 0) assumeFlatListFormat = true; + } + + elemsMeanLists = true; + } + + if(assumeFlatListFormat) + {//Parses this format: + //[[4, 6, 0, 3, 0, SRWLRadMesh(_xStart=0, _yStart=0)], + //[11, 6, 0, 3, 0, SRWLRadMesh(_xStart=0, _yStart=0)], + //[11, 6, 5, 3, 0, SRWLRadMesh(_xStart=0, _yStart=0)], + //[11, 6, 6, 3, 0, SRWLRadMesh(_xStart=0, _yStart=0)]] + + for(int j=0; j 1) + { + *(pIntDescr + 1) = -1; //to mark that only the first element of the array is defined + } + } + else + { + ParseSructSRWLRadMesh(arIntMesh, o); + if(nInt > 1) + { + (arIntMesh + 1)->ne = -1; //to mark that only the first element of the array is defined + } + } + } + } + return nInt; +} + /************************************************************************//** * Parses PyObject* to SRWLGsnBm* ***************************************************************************/ @@ -3010,6 +3205,26 @@ template void UpdatePyListNum(PyObject* oList, const T* ar, int n) //OC } } +/************************************************************************//** + * Updates Electric Field Wavefront structure in Py (excluding buffers) + ***************************************************************************/ +void UpdatePyRadMesh(PyObject* oRadMesh, SRWLRadMesh* pMesh) +{//OC19082018 + if((pMesh == 0) || (oRadMesh == 0)) throw strEr_NoObj; + + if(PyObject_SetAttrString(oRadMesh, "eStart", Py_BuildValue("d", pMesh->eStart))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "eFin", Py_BuildValue("d", pMesh->eFin))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "xStart", Py_BuildValue("d", pMesh->xStart))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "xFin", Py_BuildValue("d", pMesh->xFin))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "yStart", Py_BuildValue("d", pMesh->yStart))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "yFin", Py_BuildValue("d", pMesh->yFin))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "zStart", Py_BuildValue("d", pMesh->zStart))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "ne", Py_BuildValue("i", pMesh->ne))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "nx", Py_BuildValue("i", pMesh->nx))) throw strEr_BadRadMesh; + if(PyObject_SetAttrString(oRadMesh, "ny", Py_BuildValue("i", pMesh->ny))) throw strEr_BadRadMesh; + //Add more member updates if necessary +} + /************************************************************************//** * Updates Electric Field Wavefront structure in Py (excluding buffers) ***************************************************************************/ @@ -3030,17 +3245,18 @@ void UpdatePyWfr(PyObject* oWfr, SRWLWfr* pWfr) PyObject *oRadMesh = PyObject_GetAttrString(oWfr, "mesh"); if(oRadMesh == 0) throw strEr_BadWfr; - SRWLRadMesh &mesh = pWfr->mesh; - if(PyObject_SetAttrString(oRadMesh, "eStart", Py_BuildValue("d", mesh.eStart))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "eFin", Py_BuildValue("d", mesh.eFin))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "xStart", Py_BuildValue("d", mesh.xStart))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "xFin", Py_BuildValue("d", mesh.xFin))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "yStart", Py_BuildValue("d", mesh.yStart))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "yFin", Py_BuildValue("d", mesh.yFin))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "zStart", Py_BuildValue("d", mesh.zStart))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "ne", Py_BuildValue("i", mesh.ne))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "nx", Py_BuildValue("i", mesh.nx))) throw strEr_BadWfr; - if(PyObject_SetAttrString(oRadMesh, "ny", Py_BuildValue("i", mesh.ny))) throw strEr_BadWfr; + //SRWLRadMesh &mesh = pWfr->mesh; + //if(PyObject_SetAttrString(oRadMesh, "eStart", Py_BuildValue("d", mesh.eStart))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "eFin", Py_BuildValue("d", mesh.eFin))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "xStart", Py_BuildValue("d", mesh.xStart))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "xFin", Py_BuildValue("d", mesh.xFin))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "yStart", Py_BuildValue("d", mesh.yStart))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "yFin", Py_BuildValue("d", mesh.yFin))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "zStart", Py_BuildValue("d", mesh.zStart))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "ne", Py_BuildValue("i", mesh.ne))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "nx", Py_BuildValue("i", mesh.nx))) throw strEr_BadWfr; + //if(PyObject_SetAttrString(oRadMesh, "ny", Py_BuildValue("i", mesh.ny))) throw strEr_BadWfr; + UpdatePyRadMesh(oRadMesh, &(pWfr->mesh)); //OC19082018 Py_DECREF(oRadMesh); if(PyObject_SetAttrString(oWfr, "Rx", Py_BuildValue("d", pWfr->Rx))) throw strEr_BadWfr; @@ -3077,17 +3293,18 @@ void UpdatePyStokes(PyObject* oStk, SRWLStokes* pStk) PyObject *oRadMesh = PyObject_GetAttrString(oStk, "mesh"); if(oRadMesh == 0) throw strEr_BadStokes; - SRWLRadMesh &mesh = pStk->mesh; - if(PyObject_SetAttrString(oRadMesh, "eStart", Py_BuildValue("d", mesh.eStart))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "eFin", Py_BuildValue("d", mesh.eFin))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "xStart", Py_BuildValue("d", mesh.xStart))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "xFin", Py_BuildValue("d", mesh.xFin))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "yStart", Py_BuildValue("d", mesh.yStart))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "yFin", Py_BuildValue("d", mesh.yFin))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "zStart", Py_BuildValue("d", mesh.zStart))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "ne", Py_BuildValue("i", mesh.ne))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "nx", Py_BuildValue("i", mesh.nx))) throw strEr_BadStokes; - if(PyObject_SetAttrString(oRadMesh, "ny", Py_BuildValue("i", mesh.ny))) throw strEr_BadStokes; + //SRWLRadMesh &mesh = pStk->mesh; + //if(PyObject_SetAttrString(oRadMesh, "eStart", Py_BuildValue("d", mesh.eStart))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "eFin", Py_BuildValue("d", mesh.eFin))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "xStart", Py_BuildValue("d", mesh.xStart))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "xFin", Py_BuildValue("d", mesh.xFin))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "yStart", Py_BuildValue("d", mesh.yStart))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "yFin", Py_BuildValue("d", mesh.yFin))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "zStart", Py_BuildValue("d", mesh.zStart))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "ne", Py_BuildValue("i", mesh.ne))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "nx", Py_BuildValue("i", mesh.nx))) throw strEr_BadStokes; + //if(PyObject_SetAttrString(oRadMesh, "ny", Py_BuildValue("i", mesh.ny))) throw strEr_BadStokes; + UpdatePyRadMesh(oRadMesh, &(pStk->mesh)); //OC19082018 Py_DECREF(oRadMesh); if(PyObject_SetAttrString(oStk, "avgPhotEn", Py_BuildValue("d", pStk->avgPhotEn))) throw strEr_BadStokes; @@ -3218,6 +3435,212 @@ void UpdatePyMagFldC(PyObject* oMagFldC, SRWLMagFldC* pMagFldC) Py_DECREF(o_List); } +/************************************************************************//** + * Updates propagated intensity and corresponding meshes in Py + ***************************************************************************/ +void UpdatePyPropInt(PyObject* oInt, SRWLRadMesh* arIntMesh, char** arInts, int nInt) //OC19082018 +{ + if((oInt == 0) || (arIntMesh == 0) || (arInts == 0)) return; + + const int indMesh = 5; //keep updated + const int indInt = indMesh + 1; //keep updated + + if(!PyList_Check(oInt)) throw strEr_BadListIntProp; + int nElem = (int)PyList_Size(oInt); + //if(nElem <= indMesh) throw strEr_BadListIntProp; + if(nElem <= 0) throw strEr_BadListIntProp; //29082018 + + PyObject *o = PyList_GetItem(oInt, (Py_ssize_t)0); + if(o == 0) throw strEr_BadListIntProp; + + PyObject *oMesh=0, *oAr=0; + SRWLRadMesh *t_arIntMesh = arIntMesh; + + bool assumeFlatListFormat = false; + int nSub = 0; + if(PyList_Check(o)) + { + nSub = (int)PyList_Size(o); + if(nSub < 0) throw strEr_BadListIntProp; + if(nSub >= indInt) + { + PyObject *oSub = PyList_GetItem(o, (Py_ssize_t)indMesh); + if(strcmp(oSub->ob_type->tp_name, "SRWLRadMesh") == 0) assumeFlatListFormat = true; + } + } + + if(assumeFlatListFormat) + {//Returnes this format: + //[[4, 6, 0, 3, 0, SRWLRadMesh(..), arI], + //[11, 6, 0, 3, 0, SRWLRadMesh(..), arI], + //[11, 6, 5, 3, 0, SRWLRadMesh(..), arI], + //[11, 6, 6, 3, 0, SRWLRadMesh(..), arI]] + + for(int i=0; i::iterator it = gmBufPyObjPtr.find(pCurInt); + if(it == gmBufPyObjPtr.end()) throw strEr_FailedUpdateInt; + oAr = it->second; + if(oAr == 0) throw strEr_FailedUpdateInt; + } + if(oAr != 0) + { + if(nSub > indInt) + { + if(PyList_SetItem(o, (Py_ssize_t)indInt, oAr)) throw strEr_FailedUpdateInt; + } + else + { + if(PyList_Append(o, oAr)) throw strEr_FailedUpdateInt; + } + } + } + return; + } + + oMesh = PyList_GetItem(oInt, (Py_ssize_t)indMesh); + if(oMesh == 0) throw strEr_BadListIntProp; + + PyObject *oMeshTrue=0; + PyObject *oNewListMesh = 0; + bool elemsAreLists = false; + bool meshNeedsToBeCopied = false; + bool meshListNeedsToBeSet = false; + if(nInt > 1) + { + if(!PyList_Check(oMesh)) + { + oNewListMesh = PyList_New((Py_ssize_t)nInt); + if(oNewListMesh == 0) throw strEr_FailedUpdateInt; + + if(PyList_SetItem(oNewListMesh, (Py_ssize_t)0, oMesh)) throw strEr_FailedUpdateInt; + oMeshTrue = oMesh; + oMesh = oNewListMesh; + + meshNeedsToBeCopied = true; + meshListNeedsToBeSet = true; + } + + //if((int)PyList_Size(oMesh) < nInt) throw strEr_BadListIntProp; + elemsAreLists = true; + } + else + { + if(PyList_Check(oMesh)) elemsAreLists = true; + //else if(!PyNumber_Check(oMesh)) throw strEr_BadListIntProp; + } + + PyObject *oM=0, *oIntAr=0; + PyObject *oFunc=0, *argList=0; + + if(elemsAreLists) + { + oIntAr = PyList_New((Py_ssize_t)nInt); + } + for(int i=0; i 0))) + { + oM = PyList_GetItem(oMesh, (Py_ssize_t)i); + if(oM == 0) throw strEr_FailedUpdateInt; + + if(oMeshTrue == 0) oMeshTrue = oM; + else + { + if(oM == oMeshTrue) + {//Request to copy the mesh object in Py (because it appeared to be the same as the the previous one - this happens e.g. + //when the list of meshes is created as: [SRWLRadMesh(_eStart=wfr.mesh.eStart, _xStart=0, _yStart=0)]*3) + meshNeedsToBeCopied = true; + } + } + } + if(meshNeedsToBeCopied && (i > 0)) + { + if(oFunc == 0) + { + oFunc = PyObject_GetAttrString(oMeshTrue, "copy"); + if(oFunc == 0) throw strEr_FailedUpdateInt; + } + if(argList == 0) + { + argList = Py_BuildValue("()"); + if(argList == 0) throw strEr_FailedUpdateInt; + } + + oM = PyObject_CallObject(oFunc, argList); + if(oM == 0) throw strEr_FailedUpdateInt; + } + + if(oM == 0) throw strEr_FailedUpdateInt; + + //This copies Mesh element in Py: + //PyObject *oFunc = PyObject_GetAttrString(oMesh, "copy"); + //PyObject *argList = Py_BuildValue("()"); + //PyObject *newMesh = PyObject_CallObject(oFunc, argList); + } + else + { + oM = oMesh; + } + + UpdatePyRadMesh(oM, t_arIntMesh++); + + if(elemsAreLists && meshNeedsToBeCopied && (i > 0)) + { + if(PyList_SetItem(oMesh, (Py_ssize_t)i, oM)) throw strEr_FailedUpdateInt; + } + + char *pCurInt = arInts[i]; + if(pCurInt != 0) + { + map::iterator it = gmBufPyObjPtr.find(pCurInt); + if(it == gmBufPyObjPtr.end()) throw strEr_FailedUpdateInt; + oAr = it->second; + if(oAr == 0) throw strEr_FailedUpdateInt; + } + if(oAr != 0) + { + if(elemsAreLists) + { + if(PyList_SetItem(oIntAr, (Py_ssize_t)i, oAr)) throw strEr_FailedUpdateInt; + } + else + { + oIntAr = oAr; + } + } + } + + if(meshListNeedsToBeSet) + //if(meshNeedsToBeCopied) + { + if(PyList_SetItem(oInt, (Py_ssize_t)indMesh, oMesh)) throw strEr_FailedUpdateInt; + } + + if(nElem > indInt) + { + if(PyList_SetItem(oInt, (Py_ssize_t)indInt, oIntAr)) throw strEr_FailedUpdateInt; + } + else + { + if(PyList_Append(oInt, oIntAr)) throw strEr_FailedUpdateInt; + } +} + /************************************************************************//** * Auxiliary function: releases Python buffers ***************************************************************************/ @@ -3349,6 +3772,10 @@ void DeallocOptCntArrays(SRWLOptC* pOptCnt) ***************************************************************************/ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + if(pWfr == 0) return -1; //returning non-zero means Wfr modification did not succeed; no throwing allowed here //if((action < 0) || (action > 2)) return -1; if(action < 0) return -1; //OC151115 @@ -3356,6 +3783,9 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) map::iterator it = gmWfrPyPtr.find(pWfr); //map::const_iterator it = gmWfrPyPtr.find(pWfr); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":ModifySRWLWfr : find",&start); + if(it == gmWfrPyPtr.end()) return -1; PyObject *oWfr = it->second.o_wfr; if(oWfr == 0) return -1; @@ -3426,9 +3856,15 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) if(oFunc == 0) return -1; //OC151115 if(!PyCallable_Check(oFunc)) return -1; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : before PyObject_CallObject",&start); + PyObject *res = PyObject_CallObject(oFunc, argList); //re-allocate in Py Py_DECREF(argList); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : PyObject_CallObject",&start); + Py_DECREF(oFunc); if(res == 0) return -1; Py_DECREF(res); @@ -3452,6 +3888,9 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) if((int)it->second.pv_buf->size() > sizeVectBuf) it->second.pbEx = (*it->second.pv_buf)[sizeVectBuf]; Py_DECREF(o_tmp); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arEx",&start); + o_tmp = PyObject_GetAttrString(oWfr, "arEy"); if(o_tmp == 0) return -1; //if(PyObject_CheckBuffer(o_tmp)) @@ -3467,6 +3906,9 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) if((int)it->second.pv_buf->size() > sizeVectBuf) it->second.pbEy = (*it->second.pv_buf)[sizeVectBuf]; Py_DECREF(o_tmp); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arEy",&start); + pWfr->arExAux = 0; //OC151115 if(PyObject_HasAttrString(oWfr, "arExAux")) { @@ -3484,6 +3926,10 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) } } } + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arExAux",&start); + //if(pWfr->arExAux == 0) //{//This creates problems // if((action == 20) && ExNeeded) PyBuffer_Release(&(it->second.pbExAux)); @@ -3506,6 +3952,10 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) } } } + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arEyAux",&start); + //if(pWfr->arEyAux == 0) //{//This creates problems // if((action == 20) && EyNeeded) PyBuffer_Release(&(it->second.pbEyAux)); @@ -3526,6 +3976,9 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) if((int)it->second.pv_buf->size() > sizeVectBuf) it->second.pbMomX = (*it->second.pv_buf)[sizeVectBuf]; Py_DECREF(o_tmp); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arMomX",&start); + o_tmp = PyObject_GetAttrString(oWfr, "arMomY"); if(o_tmp == 0) return -1; //if(PyObject_CheckBuffer(o_tmp)) @@ -3540,9 +3993,45 @@ int ModifySRWLWfr(int action, SRWLWfr* pWfr, char pol) if(!(pWfr->arMomY = (double*)GetPyArrayBuf(o_tmp, it->second.pv_buf, 0))) return -1; if((int)it->second.pv_buf->size() > sizeVectBuf) it->second.pbMomY = (*it->second.pv_buf)[sizeVectBuf]; Py_DECREF(o_tmp); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::ModifySRWLWfr : arMomY",&start); + return 0; } +//void* (*pExtFunc)(char type, long long len) +/************************************************************************//** + * Array allocation function; to be called by pointer from SRWLIB + ***************************************************************************/ +char* AllocPyArrayGetBuf(char type, long long len) +{ + if(!((type == 'd') || (type == 'f') || (type == 'i'))) return 0; //returning 0 means allocation did not succeed; no throwing allowed here + if(len <= 0) return 0; + + PyObject *oSRWLIB = PyImport_AddModule("srwlib"); + PyObject *oFunc = PyObject_GetAttrString(oSRWLIB, "srwl_uti_array_alloc"); + if((oFunc == 0) || (!PyCallable_Check(oFunc))) throw strEr_FailedAllocPyArray; + +#if PY_MAJOR_VERSION >= 3 + PyObject *oArgList = Py_BuildValue("(C,l)", type, len); +#else + PyObject *oArgList = Py_BuildValue("(c,l)", type, len); +#endif + + PyObject *oAr = PyObject_CallObject(oFunc, oArgList); //allocate array in Py + Py_DECREF(oArgList); + + if(oAr == 0) throw strEr_FailedAllocPyArray; + + Py_ssize_t sizeBuf=0; + char *resBuf = GetPyArrayBuf(oAr, 0, &sizeBuf); + if((resBuf == 0) || (sizeBuf <= 0)) throw strEr_FailedAllocPyArray; + + gmBufPyObjPtr[resBuf] = oAr; //to be able to manipulate with Py objects corresponding to arrays + return resBuf; +} + /************************************************************************//** * Tabulates 3D magnetic field (in Cartesian laboratory frame); * see help to srwlCalcMagnField @@ -4068,17 +4557,31 @@ static PyObject* srwlpy_ResizeElecField(PyObject *self, PyObject *args) ***************************************************************************/ static PyObject* srwlpy_SetRepresElecField(PyObject *self, PyObject *args) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + PyObject *oWfr=0, *oRepr; vector vBuf; SRWLWfr wfr; try { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : begin",&start); + if(!PyArg_ParseTuple(args, "OO:SetRepresElecField", &oWfr, &oRepr)) throw strEr_BadArg_SetRepresElecField; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : PyArg_ParseTuple",&start); + if((oWfr == 0) || (oRepr == 0)) throw strEr_BadArg_SetRepresElecField; ParseSructSRWLWfr(&wfr, oWfr, &vBuf, gmWfrPyPtr); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : ParseSructSRWLWfr",&start); + //PyObject *o_str = PyUnicode_AsUTF8String(oRepr); //if(!PyBytes_Check(o_str)) throw strEr_BadArg_SetRepresElecField; //char repr = *PyBytes_AsString(o_str); @@ -4087,7 +4590,14 @@ static PyObject* srwlpy_SetRepresElecField(PyObject *self, PyObject *args) CopyPyStringToC(oRepr, cRepr, 1); ProcRes(srwlSetRepresElecField(&wfr, *cRepr)); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : srwlSetRepresElecField",&start); + UpdatePyWfr(oWfr, &wfr); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : UpdatePyWfr",&start); } catch(const char* erText) { @@ -4099,7 +4609,14 @@ static PyObject* srwlpy_SetRepresElecField(PyObject *self, PyObject *args) ReleasePyBuffers(vBuf); EraseElementFromMap(&wfr, gmWfrPyPtr); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : EraseElementFromMap",&start); + if(oWfr) Py_XINCREF(oWfr); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_SetRepresElecField : Py_XINCREF",&start); + return oWfr; } @@ -4109,21 +4626,70 @@ static PyObject* srwlpy_SetRepresElecField(PyObject *self, PyObject *args) ***************************************************************************/ static PyObject* srwlpy_PropagElecField(PyObject *self, PyObject *args) { - PyObject *oWfr=0, *oOptCnt=0; + //PyObject *oWfr=0, *oOptCnt=0; + PyObject *oWfr=0, *oOptCnt=0, *oInt=0; //OC14082018 + vector vBuf; SRWLWfr wfr; SRWLOptC optCnt = {0,0,0,0,0}; //since SRWL structures are definied in C (no constructors) + + //char *arIndsInt=0, *arIntType=0, *arPol=0, *arDepType=0; //OC14082018 + //double *arE=0, *arX=0, *arY=0; + char *arIntDescr[] = {0,0,0,0,0}; //OC14082018 + SRWLRadMesh *arIntMesh=0; + //float **arInts=0; + char **arInts=0; try { - if(!PyArg_ParseTuple(args, "OO:PropagElecField", &oWfr, &oOptCnt)) throw strEr_BadArg_PropagElecField; + //if(!PyArg_ParseTuple(args, "OO:PropagElecField", &oWfr, &oOptCnt)) throw strEr_BadArg_PropagElecField; + if(!PyArg_ParseTuple(args, "OO|O:PropagElecField", &oWfr, &oOptCnt, &oInt)) throw strEr_BadArg_PropagElecField; //OC14082018 if((oWfr == 0) || (oOptCnt == 0)) throw strEr_BadArg_PropagElecField; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + ParseSructSRWLWfr(&wfr, oWfr, &vBuf, gmWfrPyPtr); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_PropagElecField : ParseSructSRWLWfr", &start); + ParseSructSRWLOptC(&optCnt, oOptCnt, &vBuf); - ProcRes(srwlPropagElecField(&wfr, &optCnt)); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_PropagElecField :ParseSructSRWLOptC", &start); + + int nInt = 0; + if(oInt != 0) //OC14082018 + { + nInt = ParseSructSRWLPropIntDef(arIntDescr, arIntMesh, oInt); + if(nInt > 0) + { + //arInts = new float*[nInt]; + arInts = new char*[nInt]; + for(int i=0; i 0)) //OC14082018 + {//Find and add objects corresponding to different intensity distributions to the oInt list + UpdatePyPropInt(oInt, arIntMesh, arInts, nInt); + } + UpdatePyWfr(oWfr, &wfr); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlpy_PropagElecField :UpdatePyWfr", &start); } catch(const char* erText) { @@ -4136,6 +4702,11 @@ static PyObject* srwlpy_PropagElecField(PyObject *self, PyObject *args) ReleasePyBuffers(vBuf); EraseElementFromMap(&wfr, gmWfrPyPtr); + for(int i=0; i<4; i++) if(arIntDescr[i] != 0) delete[] arIntDescr[i]; + if(arIntMesh != 0) delete[] arIntMesh; + if(arInts != 0) delete[] arInts; + //arInts[i] should not be deleted, because these should be available in Py + if(oWfr) Py_XINCREF(oWfr); return oWfr; } @@ -4276,7 +4847,108 @@ static PyObject* srwlpy_UtiConvWithGaussian(PyObject *self, PyObject *args) } /************************************************************************//** - * Attempts to deduce parameters of peridic undulator magnetic field from tabulated field + * Calculates basic statistical characteristics of intensity distribution + ***************************************************************************/ +static PyObject* srwlpy_UtiIntInf(PyObject *self, PyObject *args) +{ + PyObject *oData=0, *oMesh=0, *oRes=0; + vector vBuf; + + try + { + if(!PyArg_ParseTuple(args, "OO:UtiIntInf", &oData, &oMesh)) throw strEr_BadArg_UtiIntInf; + if((oData == 0) || (oMesh == 0)) throw strEr_BadArg_UtiIntInf; + + char *pcData=0; + Py_ssize_t sizeBuf; + if(!(pcData = GetPyArrayBuf(oData, &vBuf, &sizeBuf))) throw strEr_BadArg_UtiIntInf; + + SRWLRadMesh mesh; + ParseSructSRWLRadMesh(&mesh, oMesh); + + //Py_buffer curBuf = vBuf[vBuf.size() - 1]; //Not compatible with old buffer enterf. + //Py_ssize_t dataItemSize = curBuf.itemsize; + + Py_ssize_t dataItemSize = (Py_ssize_t)round((sizeBuf/(mesh.ne*mesh.nx*mesh.ny))); + char typeData = 0; + if(dataItemSize == (Py_ssize_t)sizeof(float)) typeData = 'f'; + else if(dataItemSize == (Py_ssize_t)sizeof(double)) typeData = 'd'; + else throw strEr_BadArg_UtiIntInf; + + const int nInf = 7; + double resInf[nInf]; + ProcRes(srwlUtiIntInf(resInf, pcData, typeData, &mesh)); + + oRes = SetPyListOfLists(resInf, nInf, 1, (char*)"d"); + } + catch(const char* erText) + { + PyErr_SetString(PyExc_RuntimeError, erText); + } + + ReleasePyBuffers(vBuf); + + if(oRes) Py_XINCREF(oRes); + return oRes; +} + +/************************************************************************//** + * Performs misc. operations on input + ***************************************************************************/ +static PyObject* srwlpy_UtiIntProc(PyObject *self, PyObject *args) +{ + PyObject *oInt1=0, *oMesh1=0, *oInt2=0, *oMesh2=0, *oPar=0; + vector vBuf; + double *arPar=0; + + try + { + if(!PyArg_ParseTuple(args, "OOOOO:UtiIntProc", &oInt1, &oMesh1, &oInt2, &oMesh2, &oPar)) throw strEr_BadArg_UtiIntProc; + if((oInt1 == 0) || (oMesh1 == 0) || (oInt2 == 0) || (oMesh2 == 0) || (oPar == 0)) throw strEr_BadArg_UtiIntProc; + + SRWLRadMesh mesh1, mesh2; + ParseSructSRWLRadMesh(&mesh1, oMesh1); + ParseSructSRWLRadMesh(&mesh2, oMesh2); + + Py_ssize_t sizeBuf; + char *pcInt1=0; + if(!(pcInt1 = GetPyArrayBuf(oInt1, &vBuf, &sizeBuf))) throw strEr_BadArg_UtiIntProc; + + char typeInt1=0; + Py_ssize_t intItemSize = (Py_ssize_t)round((sizeBuf/(mesh1.ne*mesh1.nx*mesh1.ny))); + if(intItemSize == (Py_ssize_t)sizeof(float)) typeInt1 = 'f'; + else if(intItemSize == (Py_ssize_t)sizeof(double)) typeInt1 = 'd'; + else throw strEr_BadArg_UtiIntProc; + + char *pcInt2=0; + if(!(pcInt2 = GetPyArrayBuf(oInt2, &vBuf, &sizeBuf))) throw strEr_BadArg_UtiIntProc; + + char typeInt2=0; + intItemSize = (Py_ssize_t)round((sizeBuf/(mesh2.ne*mesh2.nx*mesh2.ny))); + if(intItemSize == (Py_ssize_t)sizeof(float)) typeInt2 = 'f'; + else if(intItemSize == (Py_ssize_t)sizeof(double)) typeInt2 = 'd'; + else throw strEr_BadArg_UtiIntProc; + + int nPar=0; + CopyPyListElemsToNumArray(oPar, 'd', arPar, nPar); + if(nPar < 1) throw strEr_BadArg_UtiIntProc; + + ProcRes(srwlUtiIntProc(pcInt1, typeInt1, &mesh1, pcInt2, typeInt2, &mesh2, arPar)); + } + catch(const char* erText) + { + PyErr_SetString(PyExc_RuntimeError, erText); + } + + ReleasePyBuffers(vBuf); + if(arPar) delete[] arPar; + + if(oInt2) Py_XINCREF(oInt2); + return oInt2; +} + +/************************************************************************//** + * Attempts to deduce parameters of periodic undulator magnetic field from tabulated field ***************************************************************************/ static PyObject* srwlpy_UtiUndFromMagFldTab(PyObject *self, PyObject *args) { @@ -4425,6 +5097,8 @@ static PyMethodDef srwlpy_methods[] = { {"PropagElecField", srwlpy_PropagElecField, METH_VARARGS, "PropagElecField() \"Propagates\" Electric Field Wavefront through Optical Elements and free space"}, {"UtiFFT", srwlpy_UtiFFT, METH_VARARGS, "UtiFFT() Performs 1D or 2D FFT (as defined by arguments)"}, {"UtiConvWithGaussian", srwlpy_UtiConvWithGaussian, METH_VARARGS, "UtiConvWithGaussian() Performs convolution of 1D or 2D data wave with 1D or 2D Gaussian (as defined by arguments)"}, + {"UtiIntInf", srwlpy_UtiIntInf, METH_VARARGS, "UtiIntInf() Calculates basic statistical characteristics of intensity distribution"}, + {"UtiIntProc", srwlpy_UtiIntProc, METH_VARARGS, "UtiIntProc() Performs misc. operations on one or two intensity distributions"}, {"UtiUndFromMagFldTab", srwlpy_UtiUndFromMagFldTab, METH_VARARGS, "UtiUndFromMagFldTab() Attempts to create periodic undulator structure from tabulated magnetic field"}, {"UtiUndFindMagFldInterpInds", srwlpy_UtiUndFindMagFldInterpInds, METH_VARARGS, "UtiUndFindMagFldInterpInds() Finds indexes of undulator gap and phase values and associated magnetic fields requiired to be used in field interpolation based on gap and phase"}, {NULL, NULL} @@ -4448,6 +5122,7 @@ PyMODINIT_FUNC PyInit_srwlpy(void) { //setting pointer to function to be eventually called from SRWLIB srwlUtiSetWfrModifFunc(&ModifySRWLWfr); + srwlUtiSetAllocArrayFunc(&AllocPyArrayGetBuf); //OC15082018 return PyModule_Create(&srwlpymodule); } @@ -4458,6 +5133,7 @@ PyMODINIT_FUNC initsrwlpy(void) { //setting pointer to function to be eventually called from SRWLIB srwlUtiSetWfrModifFunc(&ModifySRWLWfr); + srwlUtiSetAllocArrayFunc(&AllocPyArrayGetBuf); //OC15082018 Py_InitModule("srwlpy", srwlpy_methods); } diff --git a/cpp/src/core/srercode.h b/cpp/src/core/srercode.h index c84ea554..be198a8a 100644 --- a/cpp/src/core/srercode.h +++ b/cpp/src/core/srercode.h @@ -239,6 +239,10 @@ #define SRWL_INCORRECT_PARAM_FOR_SPHER_WAVE_COMP 186 + FIRST_XOP_ERR #define CAN_NOT_FIND_IND_FOR_INTERP 187 + FIRST_XOP_ERR +#define SRWL_EXT_ARRAY_ALLOC_FAILED 188 + FIRST_XOP_ERR +#define CAN_NOT_EXTRACT_MUT_INT 189 + FIRST_XOP_ERR +#define SRWL_INCORRECT_PARAM_FOR_INT_STAT 190 + FIRST_XOP_ERR +#define SRWL_INCORRECT_PARAM_FOR_INT_PROC 191 + FIRST_XOP_ERR //------------------------------------------------------------------------- /* Warning codes */ diff --git a/cpp/src/core/sroptapt.h b/cpp/src/core/sroptapt.h index 0a464d15..dd70eeff 100644 --- a/cpp/src/core/sroptapt.h +++ b/cpp/src/core/sroptapt.h @@ -16,6 +16,10 @@ #include "sroptshp.h" +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +//#include +//#include "srwlib.h" + //************************************************************************* class srTAperture : public srTShapedOptElem { diff --git a/cpp/src/core/sroptcnt.cpp b/cpp/src/core/sroptcnt.cpp index faebea15..d49ffb62 100644 --- a/cpp/src/core/sroptcnt.cpp +++ b/cpp/src/core/sroptcnt.cpp @@ -22,9 +22,13 @@ #include "sropthck.h" #include "sroptang.h" #include "sroptcryst.h" +#include "srradmnp.h" #include "auxparse.h" #include "srwlib.h" +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +//#include "stdio.h" + //************************************************************************* extern int (*pgOptElemGetInfByNameFunc)(const char* sNameOptElem, char** pDescrStr, int* pLenDescr, void*); @@ -246,14 +250,27 @@ int srTCompositeOptElem::PropagateRadiationTest(srTSRWRadStructAccessData* pInRa //************************************************************************* -int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr) +int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr, int nInt, char** arID, SRWLRadMesh* arIM, char** arI) //OC15082018 +//int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start,start1; + //get_walltime(&start); + //get_walltime(&start1); + int numElem = (int)GenOptElemList.size(); int numResizeInst = (int)GenOptElemPropResizeVect.size(); const double tolRes = 1.e-04; int res = 0, elemCount = 0; + + bool propIntIsNeeded = (nInt != 0) && (arID != 0) && (arI != 0); //OC27082018 + for(srTGenOptElemHndlList::iterator it = GenOptElemList.begin(); it != GenOptElemList.end(); ++it) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("PropagateRadiationGuided: start iteration",&start1); + //srwlPrintTime("PropagateRadiationGuided: start iteration",&start); + int methNo = 0; int useResizeBefore = 0; int useResizeAfter = 0; @@ -264,11 +281,22 @@ int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr double vLxO=0, vLyO=0, vLzO=0; //Coordinates of the output Optical Axis vector double vHxO=0, vHyO=0; //Default coordinates of the Horizontal Base vector of the output frame + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: set params",&start); + if(elemCount < numResizeInst) { srTRadResize &curPropResizeInst = GenOptElemPropResizeVect[elemCount]; useResizeBefore = curPropResizeInst.propAutoResizeBefore(); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: propAutoResizeBefore",&start); + useResizeAfter = curPropResizeInst.propAutoResizeAfter(); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: propAutoResizeAfter",&start); + if(useResizeBefore || useResizeAfter) methNo = 2; precFact = curPropResizeInst.PropAutoPrec; @@ -280,6 +308,9 @@ int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr (::fabs(curPropResizeInst.pzd - 1.) > tolRes) || (::fabs(curPropResizeInst.pzm - 1.) > tolRes)) if(res = RadResizeGen(wfr, curPropResizeInst)) return res; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: RadResizeGen",&start); + vLxO = curPropResizeInst.vLxOut; //OC021213 vLyO = curPropResizeInst.vLyOut; vLzO = curPropResizeInst.vLzOut; @@ -288,23 +319,93 @@ int srTCompositeOptElem::PropagateRadiationGuided(srTSRWRadStructAccessData& wfr } srTParPrecWfrPropag precParWfrPropag(methNo, useResizeBefore, useResizeAfter, precFact, underSampThresh, analTreatment, (char)0, vLxO, vLyO, vLzO, vHxO, vHyO); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: precParWfrPropag",&start); + srTRadResizeVect auxResizeVect; if(res = ((srTGenOptElem*)(it->rep))->PropagateRadiation(&wfr, precParWfrPropag, auxResizeVect)) return res; - //maybe to use "PropagateRadiationGuided" for srTCompositeOptElem? + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("Iteration: PropagateRadiation",&start); + + if(propIntIsNeeded) ExtractPropagatedIntensity(wfr, nInt, arID, arIM, arI, elemCount); + elemCount++; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //char str[256]; + //sprintf(str,"%s %d","PropagateRadiationGuided: Iteration :",elemCount); + //srwlPrintTime(str,&start1); } if(elemCount < numResizeInst) {//post-resize //TO IMPLEMENT: eventual shift of wavefront before resizing!!! srTRadResize &postResize = GenOptElemPropResizeVect[elemCount]; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("PropagateRadiationGuided: GenOptElemPropResizeVect",&start); + if((::fabs(postResize.pxd - 1.) > tolRes) || (::fabs(postResize.pxm - 1.) > tolRes) || (::fabs(postResize.pzd - 1.) > tolRes) || (::fabs(postResize.pzm - 1.) > tolRes)) if(res = RadResizeGen(wfr, postResize)) return res; + + if(propIntIsNeeded) ExtractPropagatedIntensity(wfr, nInt, arID, arIM, arI, elemCount); //OC29082018 + //if(propIntIsNeeded) ExtractPropagatedIntensity(wfr, nInt, arID, arIM, arI, elemCount, nInt - 1); } return 0; } //************************************************************************* + +int srTCompositeOptElem::ExtractPropagatedIntensity(srTSRWRadStructAccessData& wfr, int nInt, char** arID, SRWLRadMesh* arIM, char** arI, int elCnt, int indIntSartSearch) //27082018 +{ + if((nInt == 0) || (arID == 0) || (arI == 0)) return 0; + int res = 0; + int indInt = -1; + char *pID0 = *arID; + //char *tID0 = pID0; + char *tID0 = pID0 + indIntSartSearch; + + for(int ii=indIntSartSearch; ii 1) && (ii > 0)) + { + if(pol < 0) pol = *(arID[1]); + if(type < 0) type = *(arID[2]); + if(dep < 0) dep = *(arID[3]); + if(pres < 0) pres = *(arID[4]); + if(mesh.ne < 0) mesh = *(arIM); + } + + if(arCurI == 0) + {//Allocate memory for the intensity in the front-end via a function in srTSRWRadStructAccessData (which calculates amount of necessary memory based on type of intensity) + if(res = wfr.AllocExtIntArray(type, dep, arCurI)) return res; //OC18082018 + } + //else //? + + //Extract the intensity (repeating how this is done in srwlCalcIntFromElecField) + CHGenObj hWfr(&wfr, true); + srTRadGenManip radGenManip(hWfr); + radGenManip.ExtractRadiationSRWL(pol, type, dep, pres, mesh.eStart, mesh.xStart, mesh.yStart, arCurI); + + //Updating mesh for intensity with data from wavefront + wfr.GetIntMesh(dep, mesh); + //break; //OC29082018 (to enable intesity indexes in arbitrary order) + } + } + return res; +} + +//************************************************************************* diff --git a/cpp/src/core/sroptcnt.h b/cpp/src/core/sroptcnt.h index acb833b8..59095ccc 100644 --- a/cpp/src/core/sroptcnt.h +++ b/cpp/src/core/sroptcnt.h @@ -18,6 +18,8 @@ struct SRWLStructOpticsContainer; typedef struct SRWLStructOpticsContainer SRWLOptC; +struct SRWLStructRadMesh; +typedef struct SRWLStructRadMesh SRWLRadMesh; //************************************************************************* @@ -32,7 +34,9 @@ class srTCompositeOptElem : public srTGenOptElem { srTCompositeOptElem() {} int PropagateRadiationTest(srTSRWRadStructAccessData*, srTSRWRadStructAccessData*); - int PropagateRadiationGuided(srTSRWRadStructAccessData& wfr); + int PropagateRadiationGuided(srTSRWRadStructAccessData& wfr, int nInt=0, char** arID=0, SRWLRadMesh* arIM=0, char** arI=0); //OC15082018 + //int PropagateRadiationGuided(srTSRWRadStructAccessData& wfr); + int ExtractPropagatedIntensity(srTSRWRadStructAccessData& wfr, int nInt, char** arID, SRWLRadMesh* arIM, char** arI, int elCnt, int indIntSartSearch=0); //27082018 void AddOptElemFront(srTGenOptElemHndl& OptElemHndl) { diff --git a/cpp/src/core/sroptdrf.cpp b/cpp/src/core/sroptdrf.cpp index 6a75abd1..3ae33f05 100644 --- a/cpp/src/core/sroptdrf.cpp +++ b/cpp/src/core/sroptdrf.cpp @@ -477,12 +477,26 @@ int srTDriftSpace::PropagateRadiationSimple_AnalytTreatQuadPhaseTerm(srTSRWRadSt {// e in eV; Length in m !!! int result = 0; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + SetupPropBufVars_AnalytTreatQuadPhaseTerm(pRadAccessData); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:SetupPropBufVars_AnalytTreatQuadPhaseTerm",&start); + if(pRadAccessData->Pres != 0) if(result = SetRadRepres(pRadAccessData, 0)) return result; - + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:SetRadRepres 1",&start); + PropBufVars.PassNo = 1; //Remove quadratic term from the Phase in coord. repres. if(result = TraverseRadZXE(pRadAccessData)) return result; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:TraverseRadZXE 1",&start); + //testOC09302011 //if(Length == 34.63) return 0; @@ -498,8 +512,15 @@ int srTDriftSpace::PropagateRadiationSimple_AnalytTreatQuadPhaseTerm(srTSRWRadSt if(result = SetRadRepres(pRadAccessData, 1)) return result; //To angular repres. + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:SetRadRepres 2",&start); + PropBufVars.PassNo = 2; //Loop in angular repres. if(result = TraverseRadZXE(pRadAccessData)) return result; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:TraverseRadZXE 2",&start); + if(pRadAccessData->UseStartTrToShiftAtChangingRepresToCoord) { pRadAccessData->xStartTr += xShift; @@ -508,6 +529,9 @@ int srTDriftSpace::PropagateRadiationSimple_AnalytTreatQuadPhaseTerm(srTSRWRadSt if(result = SetRadRepres(pRadAccessData, 0)) return result; //Back to coord. repres. + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:SetRadRepres 3",&start); + pRadAccessData->xStart = xStartOld; pRadAccessData->zStart = zStartOld; if(pRadAccessData->UseStartTrToShiftAtChangingRepresToCoord) { @@ -531,8 +555,15 @@ int srTDriftSpace::PropagateRadiationSimple_AnalytTreatQuadPhaseTerm(srTSRWRadSt PropBufVars.PassNo = 3; //Add new quadratic term to the Phase in coord. repres. if(result = TraverseRadZXE(pRadAccessData)) return result; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:TraverseRadZXE 3",&start); + //pRadAccessData->MirrorFieldData(sign(kx), sign(kz)); pRadAccessData->MirrorFieldData((int)sign(PropBufVars.kx_AnalytTreatQuadPhaseTerm), (int)sign(PropBufVars.kz_AnalytTreatQuadPhaseTerm)); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AnalytTreatQuadPhaseTerm:MirrorFieldData",&start); + //if(kx < 0) if(PropBufVars.kx_AnalytTreatQuadPhaseTerm < 0) { @@ -557,6 +588,10 @@ int srTDriftSpace::PropagateRadiationSimple_AnalytTreatQuadPhaseTerm(srTSRWRadSt void srTDriftSpace::SetupPropBufVars_AnalytTreatQuadPhaseTerm(srTSRWRadStructAccessData* pRadAccessData) {// Compute any necessary buf. vars + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + PropBufVars.xc = pRadAccessData->xc; PropBufVars.zc = pRadAccessData->zc; PropBufVars.invRx = PropBufVars.invRz = 0; @@ -585,9 +620,21 @@ void srTDriftSpace::SetupPropBufVars_AnalytTreatQuadPhaseTerm(srTSRWRadStructAcc //testOC30092011 if(!PropBufVars.UseExactRxRzForAnalytTreatQuadPhaseTerm) { - if(PropBufVars.AnalytTreatSubType == 1) EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(pRadAccessData, trueRx, trueRz); + if(PropBufVars.AnalytTreatSubType == 1) + { + EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(pRadAccessData, trueRx, trueRz); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":SetupPropBufVars_AnalytTreatQuadPhaseTerm:EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm",&start); + } //OC15102011 -- under testing (disadvantage of the previous version is the dependence of "trueR" on statistical moments) - else if(PropBufVars.AnalytTreatSubType == 2) EstimateWfrRadToSub2_AnalytTreatQuadPhaseTerm(pRadAccessData, trueRx, trueRz); //OC22042013 (uncommented) + else if(PropBufVars.AnalytTreatSubType == 2) + { + EstimateWfrRadToSub2_AnalytTreatQuadPhaseTerm(pRadAccessData, trueRx, trueRz); //OC22042013 (uncommented) + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":SetupPropBufVars_AnalytTreatQuadPhaseTerm:EstimateWfrRadToSub2_AnalytTreatQuadPhaseTerm",&start); + } } //if(pRadAccessData->RobsX != 0) @@ -729,6 +776,10 @@ void srTDriftSpace::EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(srTSRWRadStruct { if(pRadAccessData == 0) return; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + const double infLarge = 1E+23; const double coefAngRange = 0.2; //0.5; //0.6; //0.1; //to tune //const double coefCoordRange = 0.1; @@ -764,8 +815,14 @@ void srTDriftSpace::EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(srTSRWRadStruct double SigXp=0, SigZp=0; //double SigX=0, SigZ=0; //OC13112010 + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:setup",&start); + if((*(MomX.pTotPhot) == 0) && (*(MomZ.pTotPhot) == 0)) ComputeRadMoments(pRadAccessData); //OC14092011 + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:ComputeRadMoments 1",&start); + char TreatExOrEz = (*(MomX.pTotPhot) >= *(MomZ.pTotPhot))? 'x' : 'z'; if(TreatExOrEz == 'x') @@ -774,7 +831,14 @@ void srTDriftSpace::EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(srTSRWRadStruct //if((!MomX.precCenMomIsOK) || (MomX.SqrtMxpxp == 0) || (MomX.SqrtMzpzp == 0) || ((abs_s1X <= pRadAccessData->RobsXAbsErr) && (!pRadAccessData->MomWereCalcNum))) {//OC13112010: uncommented ComputeRadMoments(pRadAccessData); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:ComputeRadMoments 2",&start); + MomX.ComputeCentralMoments(); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:ComputeCentralMoments 1",&start); } //SigX = MomX.SqrtMxx; SigXp = MomX.SqrtMxpxp; @@ -787,7 +851,14 @@ void srTDriftSpace::EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(srTSRWRadStruct //if((!MomZ.precCenMomIsOK) || (MomZ.SqrtMxpxp == 0) || (MomZ.SqrtMzpzp == 0) || ((abs_s1Z <= pRadAccessData->RobsZAbsErr) && (!pRadAccessData->MomWereCalcNum))) {//OC13112010: uncommented ComputeRadMoments(pRadAccessData); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:ComputeRadMoments 3",&start); + MomZ.ComputeCentralMoments(); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:ComputeCentralMoments 2",&start); } //SigX = MomZ.SqrtMxx; SigXp = MomZ.SqrtMxpxp; @@ -958,6 +1029,8 @@ void srTDriftSpace::EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm(srTSRWRadStruct } } } + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":EstimateWfrRadToSub_AnalytTreatQuadPhaseTerm:rest",&start); } //************************************************************************* diff --git a/cpp/src/core/sroptdrf.h b/cpp/src/core/sroptdrf.h index 8a2422bc..5058067b 100644 --- a/cpp/src/core/sroptdrf.h +++ b/cpp/src/core/sroptdrf.h @@ -21,6 +21,10 @@ #include "srerror.h" #endif +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +//#include +//#include "srwlib.h" + //************************************************************************* struct srTDriftPropBufVars { @@ -81,6 +85,10 @@ class srTDriftSpace : public srTGenOptElem { //int PropagateRadiation(srTSRWRadStructAccessData* pRadAccessData, int MethNo, srTRadResizeVect& ResizeBeforeAndAfterVect) int PropagateRadiation(srTSRWRadStructAccessData* pRadAccessData, srTParPrecWfrPropag& ParPrecWfrPropag, srTRadResizeVect& ResizeBeforeAndAfterVect) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + int result = 0; ChooseLocalPropMode(pRadAccessData, ParPrecWfrPropag); @@ -98,7 +106,10 @@ class srTDriftSpace : public srTGenOptElem { CErrWarn::AddWarningMessage(&gVectWarnNos, PROPAG_PREC_REDUCED_DUE_TO_MEMORY_LIMIT); } } - + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiation : LocalPropMode == -1",&start); + //if(ParPrecWfrPropag.AnalTreatment == 1) //{// Treating linear terms analytically //OC25102010: commented-out because of errors in case of partially-coherent emission and B fiber @@ -242,6 +253,10 @@ class srTDriftSpace : public srTGenOptElem { } int PropagateRadiationSimple_AngRepres(srTSRWRadStructAccessData* pRadAccessData) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + int result; double xStartOld = pRadAccessData->xStart, zStartOld = pRadAccessData->zStart; pRadAccessData->xStart = -(pRadAccessData->nx >> 1)*pRadAccessData->xStep; @@ -251,14 +266,24 @@ class srTDriftSpace : public srTGenOptElem { pRadAccessData->xWfrMin += xShift; pRadAccessData->xWfrMax += xShift; pRadAccessData->zWfrMin += zShift; pRadAccessData->zWfrMax += zShift; - pRadAccessData->WfrEdgeCorrShouldBeDone = 0; + pRadAccessData->WfrEdgeCorrShouldBeDone = 0; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AngRepres:setup",&start); if(pRadAccessData->Pres != 1) { if(result = SetRadRepres(pRadAccessData, 1)) return result; } + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AngRepres:SetRadRepres 1",&start); + if(result = TraverseRadZXE(pRadAccessData)) return result; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AngRepres:TraverseRadZXE",&start); + if(pRadAccessData->UseStartTrToShiftAtChangingRepresToCoord) { pRadAccessData->xStartTr += xShift; @@ -267,6 +292,9 @@ class srTDriftSpace : public srTGenOptElem { if(result = SetRadRepres(pRadAccessData, 0)) return result; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AngRepres:SetRadRepres 2",&start); + pRadAccessData->xStart = xStartOld; pRadAccessData->zStart = zStartOld; if(pRadAccessData->UseStartTrToShiftAtChangingRepresToCoord) @@ -276,6 +304,10 @@ class srTDriftSpace : public srTGenOptElem { } pRadAccessData->SetNonZeroWavefrontLimitsToFullRange(); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":PropagateRadiationSimple_AngRepres:SetNonZeroWavefrontLimitsToFullRange 2",&start); + return 0; } int PropagateRadiationSimple_PropToWaist(srTSRWRadStructAccessData* pRadAccessData); diff --git a/cpp/src/core/sroptel2.cpp b/cpp/src/core/sroptel2.cpp index 3a9846e2..092fc5ad 100644 --- a/cpp/src/core/sroptel2.cpp +++ b/cpp/src/core/sroptel2.cpp @@ -16,6 +16,14 @@ #include "srmlttsk.h" #include "srerror.h" +//OC31102018: added by SY at parallelizing SRW via OpenMP +//#include "srwlib.h" +//#include "stdio.h" + +#ifdef _WITH_OMP //OC31102018: added by SY at parallelizing SRW via OpenMP +#include "omp.h" +#endif + extern srTYield srYield; //************************************************************************* @@ -35,9 +43,15 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces //in the "slices". //It is virtual ("standard" processing). Known re-definitions: in srTDriftSpace - srTSRWRadStructAccessData *pRadDataSingleE = 0, *pPrevRadDataSingleE = 0; - + //OC31102018: added by SY at parallelizing SRW via OpenMP + //double start; + //get_walltime (&start); + int result=0; + +#ifndef _WITH_OMP //OC31102018 + + srTSRWRadStructAccessData *pRadDataSingleE = 0, *pPrevRadDataSingleE = 0; if(pRadAccessData->ne == 1) { pRadDataSingleE = pRadAccessData; @@ -125,6 +139,149 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces if((pRadDataSingleE != 0) && (pRadDataSingleE != pRadAccessData)) delete pRadDataSingleE; if((pPrevRadDataSingleE != 0) && (pPrevRadDataSingleE != pRadAccessData)) delete pPrevRadDataSingleE; + +#else //OC31102018: modified by SY at parallelizing SRW via OpenMP + + if(pRadAccessData->ne == 1) + { + //SY: nothing more is actually needed in this case + return PropagateRadiationSingleE_Meth_0(pRadAccessData, 0); //from derived classes + + //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP + //srwlPrintTime(": PropagateRadiationMeth_0 : PropagateRadiationSingleE_Meth_0 - single",&start); + } + + srTSRWRadStructAccessData *pPrevRadDataSingleE = 0; + + if(!m_PropWfrInPlace) + { + if(result = SetupNewRadStructFromSliceConstE(pRadAccessData, -1, pPrevRadDataSingleE)) return result; + } + + //separate processing of wavefront radius is necessary + double origRobsX = pRadAccessData->RobsX, origRobsXAbsErr = pRadAccessData->RobsXAbsErr; + double origRobsZ = pRadAccessData->RobsZ, origRobsZAbsErr = pRadAccessData->RobsZAbsErr; + double origXc = pRadAccessData->xc; //OC180813 + double origZc = pRadAccessData->zc; + + const int AmOfMoments = 11; + int neOrig = pRadAccessData->ne; + + vector vRadSlices; //to keep grid parameters of slices for eventual change of the main 3D grid and re-interpolation at the end + srTSRWRadStructAccessData** pRadSlices= new srTSRWRadStructAccessData* [neOrig]; + + bool gridParamWereModifInSlices = false; + bool* gridParamWereModif = new bool[neOrig]; + + //SY: return outside of parallel regions is not allowed - we do it outside + + int* results = new int[neOrig]; + if(results == 0) return MEMORY_ALLOCATION_FAILURE; + for(int ie = 0; ie < neOrig; ie++) results[ie] = 0; + + //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP + //srwlPrintTime(": PropagateRadiationMeth_0 : before cycle",&start); + + //SY: we cannot do it in parallel if previous field is needed (which is not the case in the current version of SRW) + #pragma omp parallel if (pPrevRadDataSingleE == 0) + { + int threadNum = omp_get_thread_num(); + srTSRWRadStructAccessData *pRadDataSingleE = 0; + results[threadNum] = SetupNewRadStructFromSliceConstE(pRadAccessData, -1, pRadDataSingleE); + //allocates new pRadDataSingleE ! + if(!results[threadNum]) + { + #pragma omp for + for(int ie=0; iepBaseRadX, pRadDataSingleE->pBaseRadZ)) continue; + pRadDataSingleE->eStart = pRadAccessData->eStart + ie*pRadAccessData->eStep; + long OffsetMom = AmOfMoments*ie; + pRadDataSingleE->pMomX = pRadAccessData->pMomX + OffsetMom; + pRadDataSingleE->pMomZ = pRadAccessData->pMomZ + OffsetMom; + pRadDataSingleE->RobsX = origRobsX; pRadDataSingleE->RobsXAbsErr = origRobsXAbsErr; + pRadDataSingleE->RobsZ = origRobsZ; pRadDataSingleE->RobsZAbsErr = origRobsZAbsErr; + + pRadDataSingleE->xc = origXc; //OC180813 + pRadDataSingleE->zc = origZc; + + //if(pRadAccessData->xStart != pRadDataSingleE->xStart) pRadDataSingleE->xStart = pRadAccessData->xStart; + //if(pRadAccessData->xStep != pRadDataSingleE->xStep) pRadDataSingleE->xStep = pRadAccessData->xStep; + //if(pRadAccessData->zStart != pRadDataSingleE->zStart) pRadDataSingleE->zStart = pRadAccessData->zStart; + //if(pRadAccessData->zStep != pRadDataSingleE->zStep) pRadDataSingleE->zStep = pRadAccessData->zStep; + pRadDataSingleE->xStart = pRadAccessData->xStart; + pRadDataSingleE->xStep = pRadAccessData->xStep; + pRadDataSingleE->zStart = pRadAccessData->zStart; + pRadDataSingleE->zStep = pRadAccessData->zStep; + + if(pPrevRadDataSingleE != 0) + { + if(results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, pPrevRadDataSingleE->pBaseRadX, pPrevRadDataSingleE->pBaseRadZ, true)) continue; //OC120908 + pPrevRadDataSingleE->eStart = pRadDataSingleE->eStart; + pPrevRadDataSingleE->pMomX = pRadDataSingleE->pMomX; + pPrevRadDataSingleE->pMomZ = pRadDataSingleE->pMomZ; + } + if(results[ie] = PropagateRadiationSingleE_Meth_0(pRadDataSingleE, pPrevRadDataSingleE)) continue; //from derived classes + + if(results[ie] = UpdateGenRadStructSliceConstE_Meth_0(pRadDataSingleE, ie, pRadAccessData,1)) continue; + //the above doesn't change the transverse grid parameters in *pRadAccessData + + //vRadSlices.push_back(*pRadDataSingleE); //this automatically calls destructor, which can eventually delete "emulated" structs! + //srTSRWRadStructAccessData copyRadDataSingleE(*pRadDataSingleE); //this doesn't assume to copy pBaseRadX, pBaseRadZ + //srTSRWRadStructAccessData copyRadDataSingleE(*pRadDataSingleE, false); //OC290813 fixing memory leak(?) //this doesn't assume to copy pBaseRadX, pBaseRadZ + //SY: we cannot use push here, so use normal array instead (probably using of vector would be still possible, but just to be sure) + + pRadSlices[ie] = new srTSRWRadStructAccessData(*pRadDataSingleE, false); + pRadSlices[ie]->pBaseRadX = pRadSlices[ie]->pBaseRadZ = 0; pRadSlices[ie]->BaseRadWasEmulated = false; + + if((pRadDataSingleE->nx != pRadAccessData->nx) || (pRadDataSingleE->xStart != pRadAccessData->xStart) || (pRadDataSingleE->xStep != pRadAccessData->xStep)) gridParamWereModif[ie] = true; + if((pRadDataSingleE->nz != pRadAccessData->nz) || (pRadDataSingleE->zStart != pRadAccessData->zStart) || (pRadDataSingleE->zStep != pRadAccessData->zStep)) gridParamWereModif[ie] = true; + } + } + if(pRadDataSingleE != 0) delete pRadDataSingleE; + } + + for(int ie = 0; ie < neOrig; ie++) if(results[ie]) return results[ie]; + delete[] results; + + //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP + //char str[256]; + //sprintf(str,"%s %d",":PropagateRadiationMeth_0 : PropagateRadiationSingleE_Meth_0 - cycles:",neOrig); + //srwlPrintTime(str,&start); + + //SY: update limits and Radii (cannot be done in parallel) + for(int ie = 0; ie < neOrig; ie++) if(result = UpdateGenRadStructSliceConstE_Meth_0(pRadSlices[ie], ie, pRadAccessData,2)) return result; + + //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP + //srwlPrintTime(":PropagateRadiationMeth_0 : UpdateGenRadStructSliceConstE_Meth_0:",&start); + + if((pRadAccessData->RobsX != 0) && (pRadAccessData->RobsXAbsErr == 0)) pRadAccessData->RobsXAbsErr = ::fabs(0.1*pRadAccessData->RobsX); + if((pRadAccessData->RobsZ != 0) && (pRadAccessData->RobsZAbsErr == 0)) pRadAccessData->RobsZAbsErr = ::fabs(0.1*pRadAccessData->RobsZ); + + for(int i=0;ine << 1; long long PerZ = PerX*pRadAccessData->nx; +#ifndef _WITH_OMP //OC28102018 + srTEFieldPtrs EFieldPtrs; srTEXZ EXZ; EXZ.z = pRadAccessData->zStart; //long izPerZ = 0; //long iTotTest = 0; //OCTEST long long izPerZ = 0; - long long iTotTest = 0; //OCTEST + //long long iTotTest = 0; //OCTEST - int result = 0; + //int result = 0; for(int iz=0; iznz; iz++) { - if(result = srYield.Check()) return result; + //if(result = srYield.Check()) return result; float *pEx_StartForX = pEx0 + izPerZ; float *pEz_StartForX = pEz0 + izPerZ; @@ -168,13 +174,6 @@ int srTGenOptElem::TraverseRadZXE(srTSRWRadStructAccessData* pRadAccessData) //long iePerE = 0; long long iePerE = 0; - //DEBUG - //if((iz == ((pRadAccessData->nz)>>1)) && (ix == ((pRadAccessData->nx)>>1))) - //{ - // int aha = 1; - //} - //END DEBUG - for(int ie=0; iene; ie++) { if(pEx0 != 0) @@ -201,7 +200,7 @@ int srTGenOptElem::TraverseRadZXE(srTSRWRadStructAccessData* pRadAccessData) EXZ.aux_offset = izPerZ + ixPerX + iePerE; RadPointModifier(EXZ, EFieldPtrs); - iTotTest++; //OCTEST + //iTotTest++; //OCTEST iePerE += 2; EXZ.e += pRadAccessData->eStep; @@ -212,6 +211,72 @@ int srTGenOptElem::TraverseRadZXE(srTSRWRadStructAccessData* pRadAccessData) izPerZ += PerZ; EXZ.z += pRadAccessData->zStep; } + +#else //OC28102018 (does this really need to be parallelized for OpenMP?) + //SY: adapted for OpenMP + + #pragma omp parallel for if (omp_get_num_threads()==1) // to avoid nested multi-threading + for(int iz=0; iznz; iz++) + { + srTEFieldPtrs EFieldPtrs; + long long izPerZ = iz*PerZ; + srTEXZ EXZ; + + //SY: to have one-to-one with previous version (so that tests do no fail) + //EXZ.z = pRadAccessData->zStart; + //for(int i=0; izStep; + //SY: can be replaced with this + EXZ.z = (pRadAccessData->zStart) + iz*(pRadAccessData->zStep); + + float *pEx_StartForX = pEx0 + izPerZ; + float *pEz_StartForX = pEz0 + izPerZ; + EXZ.x = pRadAccessData->xStart; + //long ixPerX = 0; + long long ixPerX = 0; + + for(int ix=0; ixnx; ix++) + { + float *pEx_StartForE = pEx_StartForX + ixPerX; + float *pEz_StartForE = pEz_StartForX + ixPerX; + EXZ.e = pRadAccessData->eStart; + //long iePerE = 0; + long long iePerE = 0; + + for(int ie=0; iene; ie++) + { + if(pEx0 != 0) + { + EFieldPtrs.pExRe = pEx_StartForE + iePerE; + EFieldPtrs.pExIm = EFieldPtrs.pExRe + 1; + } + else + { + EFieldPtrs.pExRe = 0; + EFieldPtrs.pExIm = 0; + } + if(pEz0 != 0) + { + EFieldPtrs.pEzRe = pEz_StartForE + iePerE; + EFieldPtrs.pEzIm = EFieldPtrs.pEzRe + 1; + } + else + { + EFieldPtrs.pEzRe = 0; + EFieldPtrs.pEzIm = 0; + } + + EXZ.aux_offset = izPerZ + ixPerX + iePerE; + RadPointModifier(EXZ, EFieldPtrs); + + iePerE += 2; + EXZ.e += pRadAccessData->eStep; + } + ixPerX += PerX; + EXZ.x += pRadAccessData->xStep; + } + } +#endif + return 0; } @@ -519,65 +584,79 @@ int srTGenOptElem::UpdateGenRadStructFromSlicesConstE_Meth_0(srTSRWRadStructAcce **/ //************************************************************************* -int srTGenOptElem::UpdateGenRadStructSliceConstE_Meth_0(srTSRWRadStructAccessData* pRadDataSliceConstE, int ie, srTSRWRadStructAccessData* pRadAccessData) +//int srTGenOptElem::UpdateGenRadStructSliceConstE_Meth_0(srTSRWRadStructAccessData* pRadDataSliceConstE, int ie, srTSRWRadStructAccessData* pRadAccessData) +//OC28102018: modified by S.Yakubov to prepare the code for OpenMP parallelization +int srTGenOptElem::UpdateGenRadStructSliceConstE_Meth_0(srTSRWRadStructAccessData* pRadDataSliceConstE, int ie, srTSRWRadStructAccessData* pRadAccessData, int update_mode) {//Compose the Electric Field of the pRadAccessData from the slices ConstE. //The slices are assumed to have same dimensions over nx and nz. - if((pRadAccessData == 0) || (pRadDataSliceConstE == 0) || (ie < 0)) return 0; - float *pEx0 = pRadAccessData->pBaseRadX; - float *pEz0 = pRadAccessData->pBaseRadZ; - - int neCom = pRadAccessData->ne; - int nxCom = pRadAccessData->nx; - int nzCom = pRadAccessData->nz; - if(neCom <= 0) return 0; - - //long PerX = neCom << 1; - //long PerZ = PerX*nxCom; - long long PerX = neCom << 1; - long long PerZ = PerX*nxCom; +// SY: update_mode - 1 - compose Electric Field only +// 2 - updates limits and Radii only +// 0 - do all (default) +// modes are needed for OpenMP stuff - //long izPerZ = 0; - //long iePerE = ie << 1; - long long izPerZ = 0; - long long iePerE = ie << 1; - float *tSliceEx = pRadDataSliceConstE->pBaseRadX; - float *tSliceEz = pRadDataSliceConstE->pBaseRadZ; + if((pRadAccessData == 0) || (pRadDataSliceConstE == 0) || (ie < 0)) return 0; - for(int iz=0; izpBaseRadX; + float *pEz0 = pRadAccessData->pBaseRadZ; + + int neCom = pRadAccessData->ne; + int nxCom = pRadAccessData->nx; + int nzCom = pRadAccessData->nz; + if(neCom <= 0) return 0; + + //long PerX = neCom << 1; + //long PerZ = PerX*nxCom; + long long PerX = neCom << 1; + long long PerZ = PerX*nxCom; + + //long izPerZ = 0; + //long iePerE = ie << 1; + long long izPerZ = 0; + long long iePerE = ie << 1; + float *tSliceEx = pRadDataSliceConstE->pBaseRadX; + float *tSliceEz = pRadDataSliceConstE->pBaseRadZ; - for(int ix=0; ixnx; ix++) + for(int iz=0; iznx; ix++) + { + //long ixPerX_p_iePerE = ixPerX + iePerE; + long long ixPerX_p_iePerE = ixPerX + iePerE; + float *pEx = pEx_StartForX + ixPerX_p_iePerE; + float *pEz = pEz_StartForX + ixPerX_p_iePerE; - ixPerX += PerX; + *(pEx++) = *(tSliceEx++); *pEx = *(tSliceEx++); + *(pEz++) = *(tSliceEz++); *pEz = *(tSliceEz++); + + ixPerX += PerX; + } + izPerZ += PerZ; } - izPerZ += PerZ; } - //Update wavefront limits in the main rad. structure: - if(pRadAccessData->xWfrMin > pRadDataSliceConstE->xWfrMin) pRadAccessData->xWfrMin = pRadDataSliceConstE->xWfrMin; - if(pRadAccessData->xWfrMax < pRadDataSliceConstE->xWfrMax) pRadAccessData->xWfrMax = pRadDataSliceConstE->xWfrMax; - if(pRadAccessData->zWfrMin > pRadDataSliceConstE->zWfrMin) pRadAccessData->zWfrMin = pRadDataSliceConstE->zWfrMin; - if(pRadAccessData->zWfrMax < pRadDataSliceConstE->zWfrMax) pRadAccessData->zWfrMax = pRadDataSliceConstE->zWfrMax; - - //Update wavefront radii in the main rad. structure (making average?): - double inv_ie_p_1 = 1./(ie + 1); - pRadAccessData->RobsX = (ie*(pRadAccessData->RobsX) + pRadDataSliceConstE->RobsX)*inv_ie_p_1; - pRadAccessData->RobsZ = (ie*(pRadAccessData->RobsZ) + pRadDataSliceConstE->RobsZ)*inv_ie_p_1; - pRadAccessData->RobsXAbsErr = (ie*(pRadAccessData->RobsXAbsErr) + pRadDataSliceConstE->RobsXAbsErr)*inv_ie_p_1; - pRadAccessData->RobsZAbsErr = (ie*(pRadAccessData->RobsZAbsErr) + pRadDataSliceConstE->RobsZAbsErr)*inv_ie_p_1; + if(update_mode == 2 || update_mode == 0) //OC28102018: added by S.Yakubov to prepare the code for OpenMP parallelization + { + //Update wavefront limits in the main rad. structure: + if(pRadAccessData->xWfrMin > pRadDataSliceConstE->xWfrMin) pRadAccessData->xWfrMin = pRadDataSliceConstE->xWfrMin; + if(pRadAccessData->xWfrMax < pRadDataSliceConstE->xWfrMax) pRadAccessData->xWfrMax = pRadDataSliceConstE->xWfrMax; + if(pRadAccessData->zWfrMin > pRadDataSliceConstE->zWfrMin) pRadAccessData->zWfrMin = pRadDataSliceConstE->zWfrMin; + if(pRadAccessData->zWfrMax < pRadDataSliceConstE->zWfrMax) pRadAccessData->zWfrMax = pRadDataSliceConstE->zWfrMax; + + //Update wavefront radii in the main rad. structure (making average?): + double inv_ie_p_1 = 1./(ie + 1); + pRadAccessData->RobsX = (ie*(pRadAccessData->RobsX) + pRadDataSliceConstE->RobsX)*inv_ie_p_1; + pRadAccessData->RobsZ = (ie*(pRadAccessData->RobsZ) + pRadDataSliceConstE->RobsZ)*inv_ie_p_1; + pRadAccessData->RobsXAbsErr = (ie*(pRadAccessData->RobsXAbsErr) + pRadDataSliceConstE->RobsXAbsErr)*inv_ie_p_1; + pRadAccessData->RobsZAbsErr = (ie*(pRadAccessData->RobsZAbsErr) + pRadDataSliceConstE->RobsZAbsErr)*inv_ie_p_1; + } //assuming that the mesh in all slices is transformed the same way //if(ie == (pRadAccessData->ne - 1)) //OC151008 //commented-out @@ -587,11 +666,9 @@ int srTGenOptElem::UpdateGenRadStructSliceConstE_Meth_0(srTSRWRadStructAccessDat // if(pRadAccessData->zStart != pRadDataSliceConstE->zStart) pRadAccessData->zStart = pRadDataSliceConstE->zStart; // if(pRadAccessData->zStep != pRadDataSliceConstE->zStep) pRadAccessData->zStep = pRadDataSliceConstE->zStep; //} - return 0; } - //************************************************************************* int srTGenOptElem::UpdateGenRadStructSliceConstE_Meth_2(srTSRWRadStructAccessData* pRadDataSliceConstE, int ie, srTSRWRadStructAccessData* pRadAccessData) @@ -1106,6 +1183,10 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char {// 0- to coord.; 1- to ang. int result; + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + char WfrEdgeCorrShouldBeTreated = pRadAccessData->WfrEdgeCorrShouldBeDone; // Turn on/off here if(pRadAccessData->Pres == CoordOrAng) return 0; @@ -1129,10 +1210,13 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char } //End New - CGenMathFFT2D FFT2D; + //CGenMathFFT2D FFT2D; + //OC28102018 (modified by SY) if(pRadAccessData->ne == 1) { + CGenMathFFT2D FFT2D; //OC28102018 (modified by SY) + srTDataPtrsForWfrEdgeCorr DataPtrsForWfrEdgeCorr; if(WfrEdgeCorrShouldBeTreated) { @@ -1181,6 +1265,11 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char //This is the original version; works by "slices" //long TwoNxNz = (pRadAccessData->nx*pRadAccessData->nz) << 1; long long TwoNxNz = (((long long)(pRadAccessData->nx))*((long long)(pRadAccessData->nz))) << 1; + + CGenMathFFT2D FFT2D; //OC28102018 (modified by SY) + +#ifndef _WITH_OMP //OC28102018 + float* AuxEx = new float[TwoNxNz]; if(AuxEx == 0) return MEMORY_ALLOCATION_FAILURE; float* AuxEz = new float[TwoNxNz]; @@ -1222,12 +1311,100 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char if(result = SetupRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz)) return result; } - if(AuxEx != 0) delete[] AuxEx; if(AuxEz != 0) delete[] AuxEz; //} +#else //OC28102018: modified by SY + + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("SetRadRepres : setup",&start); + + //SY: return outside of parallel regions is not allowed - we do it outside + + int* results = new int[pRadAccessData->ne]; + if(results == 0) return MEMORY_ALLOCATION_FAILURE; + for(long ie = 0; ie < pRadAccessData->ne; ie++) results[ie]=0; + + //SY: creation (and deletion) of FFTW plans is not thread-safe. Have to do this outside of threads. + //(and we don't need to recreate plans for same dimensions anyway) + fftwnd_plan Plan2DFFT; + if(FFT2DInfo.Dir > 0) Plan2DFFT = fftw2d_create_plan(FFT2DInfo.Ny, FFT2DInfo.Nx, FFTW_FORWARD, FFTW_IN_PLACE|FFTW_THREADSAFE); + else Plan2DFFT = fftw2d_create_plan(FFT2DInfo.Ny, FFT2DInfo.Nx, FFTW_BACKWARD, FFTW_IN_PLACE|FFTW_THREADSAFE); + + #pragma omp parallel + { + CGenMathFFT2D FFT2D; + + //SY: allocate arrays for each thread (not for each ie) + float* AuxEx = new float[TwoNxNz]; + float* AuxEz = new float[TwoNxNz]; + if(AuxEz != 0 && AuxEz!=0) + { + #pragma omp for + for(long ie = 0; ie < pRadAccessData->ne; ie++) + { + //SY: use private variable FFT2DInfo_local instead of FFT2DInfo as its + //members are changed inside Make2DFFT. + CGenMathFFT2DInfo FFT2DInfo_local = FFT2DInfo; + + if(results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz)) continue; + + srTDataPtrsForWfrEdgeCorr DataPtrsForWfrEdgeCorr; + if(WfrEdgeCorrShouldBeTreated) + { + if(CoordOrAng == 1) + { + if(results[ie] = SetupWfrEdgeCorrData(pRadAccessData, AuxEx, AuxEz, DataPtrsForWfrEdgeCorr)) continue; + } + } + + //After the FFT, all slices will be authomatically brought to the same mesh + if(ar_xStartInSlicesE != 0) FFT2DInfo_local.xStart = ar_xStartInSlicesE[ie]; + if(ar_zStartInSlicesE != 0) FFT2DInfo_local.yStart = ar_zStartInSlicesE[ie]; + + FFT2DInfo_local.pData = AuxEx; + if(results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local,&Plan2DFFT)) continue; + + FFT2DInfo_local.pData = AuxEz; + if(results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local,&Plan2DFFT)) continue; + + if(WfrEdgeCorrShouldBeTreated) + { + if(CoordOrAng == 1) + { + if(DataPtrsForWfrEdgeCorr.WasSetup) + { + MakeWfrEdgeCorrection(pRadAccessData, AuxEx, AuxEz, DataPtrsForWfrEdgeCorr); + DataPtrsForWfrEdgeCorr.DisposeData(); + } + } + } + results[ie] = SetupRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz); + //SY: save FFT2DInfo from one of FFT2DInfo_local + if(ie == 0) FFT2DInfo = FFT2DInfo_local; + } // end for + } + else + { + results[omp_get_thread_num()] = MEMORY_ALLOCATION_FAILURE; + } // end if + if(AuxEx != 0) delete[] AuxEx; + if(AuxEz != 0) delete[] AuxEz; + + } // end omp parallel + + fftwnd_destroy_plan(Plan2DFFT); + + for(long ie = 0; ie < pRadAccessData->ne; ie++) if(results[ie]) return results[ie]; + delete[] results; +#endif } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //char str[256]; + //sprintf(str,"%s %d","::SetRadRepres : cycles:",pRadAccessData->ne); + //srwlPrintTime(str,&start); + pRadAccessData->xStep = FFT2DInfo.xStepTr; pRadAccessData->zStep = FFT2DInfo.yStepTr; pRadAccessData->xStart = FFT2DInfo.xStartTr; @@ -1323,6 +1500,10 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc {// Here Lengths are in m and Phot energy in eV! // This function seems to work correctly only in Frequency-Coordinate representation + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + if((pSRWRadStructAccessData->nx <= 1) && (pSRWRadStructAccessData->nz <= 1)) return 0; //OC090112 or return error? const double TwoPi = 3.141592653590*2.; @@ -1331,10 +1512,14 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc const double Inv_eV_In_m = 1.239842E-06; srTAuxMatStat AuxMatStat; //OC13112010 (uncommented) - int IndLims[4]; + //int IndLims[4]; //OC28102018 const double RelPowForLimits = 0.9; //to steer +#ifndef _WITH_OMP //OC28102018 CHGenObj hRad(pSRWRadStructAccessData, true); //OC13112010 + double SumsX[22], SumsZ[22], ff[22]; //OC28102018 + int IndLims[4]; //OC28102018 +#endif int result = 0; //if(pSRWRadStructAccessData->Pres != 0) @@ -1353,7 +1538,10 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc WaveFrontTermWasTreated = 1; } - double SumsX[22], SumsZ[22], ff[22]; + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":ComputeRadMoments : TreatStronglyOscillatingTerm 1",&start); + + //double SumsX[22], SumsZ[22], ff[22]; //OC28102018 float *fpX0 = pSRWRadStructAccessData->pBaseRadX; float *fpZ0 = pSRWRadStructAccessData->pBaseRadZ; @@ -1368,11 +1556,13 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc int nx_mi_1 = pSRWRadStructAccessData->nx - 1; int nz_mi_1 = pSRWRadStructAccessData->nz - 1; - double ePh = pSRWRadStructAccessData->eStart; //This assumes wavefront in Time domain; Photon Energy in eV ! + //double ePh = pSRWRadStructAccessData->eStart; //This assumes wavefront in Time (Frequency?!) domain; Photon Energy in eV ! + //OC28102018 (commented-out, moved into cycle, as suggested by SY) //If wavefront is in Time-domain representation, average photon energy should be used - //float *fpMomX = pSRWRadStructAccessData->pMomX, *fpMomZ = pSRWRadStructAccessData->pMomZ; - double *fpMomX = pSRWRadStructAccessData->pMomX, *fpMomZ = pSRWRadStructAccessData->pMomZ; //130311 + //double *fpMomX = pSRWRadStructAccessData->pMomX, *fpMomZ = pSRWRadStructAccessData->pMomZ; //OC130311 + //OC28102018 (commented-out, moved into cycle, as suggested by SY) + int AmOfMom = 11; double InvStepX = 1./pSRWRadStructAccessData->xStep; @@ -1383,8 +1573,25 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc char ActualScanZ = (pSRWRadStructAccessData->nz > 1); char ActualScansXZ = (ActualScanX && ActualScanZ); + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":ComputeRadMoments : setup",&start); + +#ifdef _WITH_OMP //OC28102018: added by SY + #pragma omp parallel for +#endif + for(int ie=0; iene; ie++) { +#ifdef _WITH_OMP //OC28102018: modified by SY + CHGenObj hRad(pSRWRadStructAccessData, true); //OC13112010 + double SumsX[22], SumsZ[22], ff[22]; + int IndLims[4]; +#endif + //If wavefront is in Time-domain representation, average photon energy should be used + double *fpMomX = pSRWRadStructAccessData->pMomX + ie*AmOfMom; + double *fpMomZ = pSRWRadStructAccessData->pMomZ + ie*AmOfMom; //OC130311 + double ePh = pSRWRadStructAccessData->eStart + pSRWRadStructAccessData->eStep*ie; //This assumes wavefront in Time domain; Photon Energy in eV ! + if(!IsFreqRepres) { ePh = pSRWRadStructAccessData->avgPhotEn; //?? OC041108 @@ -1430,7 +1637,7 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc for(int iz=0; iznz; iz++) //for(int iz=IndLims[2]; iz<=IndLims[3]; iz++) { - if(result = srYield.Check()) return result; + //if(result = srYield.Check()) return result; //OC28102018 (commented-out due to potential incompatibility with OpenMP parallelization) bool vertCoordInsidePowLim = ((iz >= IndLims[2]) && (iz <= IndLims[3])); @@ -1753,11 +1960,21 @@ int srTGenOptElem::ComputeRadMoments(srTSRWRadStructAccessData* pSRWRadStructAcc } } - ePh += pSRWRadStructAccessData->eStep; - fpMomX += AmOfMom; fpMomZ += AmOfMom; + //ePh += pSRWRadStructAccessData->eStep; + //fpMomX += AmOfMom; fpMomZ += AmOfMom; + //OC28102018 (commented-out, following suggestion of SY) } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //char str[256]; + //sprintf(str,"%s %d",":ComputeRadMoments : cycles:",pSRWRadStructAccessData->ne); + //srwlPrintTime(str,&start); + if(WaveFrontTermWasTreated) TreatStronglyOscillatingTerm(*pSRWRadStructAccessData, 'a'); + + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":ComputeRadMoments : TreatStronglyOscillatingTerm 2",&start); + pSRWRadStructAccessData->MomWereCalcNum = true; return 0; } @@ -1913,6 +2130,10 @@ void srTGenOptElem::FindMinMaxRatio(double* Arr1, double* Arr2, int n, double& M int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessData, srTRadResize& RadResizeStruct) { + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime(&start); + if((RadResizeStruct.pxm == 1.) && (RadResizeStruct.pxd == 1.) && (RadResizeStruct.pzm == 1.) && (RadResizeStruct.pzd == 1.)) return 0; int result = 0; @@ -1968,6 +2189,9 @@ int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessDat long NewNx = SRWRadStructAccessData.nx; long NewNz = SRWRadStructAccessData.nz; + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: set parameters",&start); + CGenMathFFT2D FFT; char RadShouldBeChanged = ((pxTot != 1.) || (pzTot != 1.)); if(RadShouldBeChanged) @@ -1987,6 +2211,9 @@ int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessDat NewSRWRadStructAccessData.nz = NewNz; } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: if RadShouldBeChanged",&start); + char CenterIsOffset = 0; long iXc = (SRWRadStructAccessData.nx >> 1); @@ -2138,6 +2365,9 @@ int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessDat } } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: CenterIsOffset",&start); + //long TotAmOfOldData = (SRWRadStructAccessData.ne*SRWRadStructAccessData.nx*SRWRadStructAccessData.nz) << 1; //long TotAmOfNewData = (NewSRWRadStructAccessData.ne*NewSRWRadStructAccessData.nx*NewSRWRadStructAccessData.nz) << 1; long long TotAmOfOldData = (((long long)SRWRadStructAccessData.ne)*((long long)SRWRadStructAccessData.nx)*((long long)SRWRadStructAccessData.nz)) << 1; @@ -2155,6 +2385,9 @@ int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessDat TreatPolarizSepar = (ExtraMemSize > SecurityMemResizeCoef*MemoryAvail)? 1 : 0; } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: TreatPolarizSepar memory",&start); + float *OldRadXCopy = 0, *OldRadZCopy = 0; if(!TreatPolarizSepar) { @@ -2175,32 +2408,56 @@ int srTGenOptElem::RadResizeGen(srTSRWRadStructAccessData& SRWRadStructAccessDat *(tOldRadXCopy++) = *(tBaseRadX++); *(tOldRadZCopy++) = *(tBaseRadZ++); } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: memalloc",&start); if(RadShouldBeChanged) { if(NewSRWRadStructAccessData.BaseRadWasEmulated) { if(result = NewSRWRadStructAccessData.ReAllocBaseRadAccordingToNeNxNz()) return result; + + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: TreatPolarizSepar-ReAllocBaseRadAccordingToNeNxNz",&start); } //else if(result = Send.ModifyRadNeNxNz(NewSRWRadStructAccessData)) return result; else if(result = NewSRWRadStructAccessData.ModifyWfrNeNxNz()) return result; + + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: ModifyWfrNeNxNz",&start); } + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeGen: RadShouldBeChanged",&start); tBaseRadX = NewSRWRadStructAccessData.pBaseRadX; tBaseRadZ = NewSRWRadStructAccessData.pBaseRadZ; - //for(long j=0; j= 1.) && (RadResizeStruct.pzm >= 1.)) && ((::fabs(OldRadAccessData.xStep - NewRadAccessData.xStep) < RelStepTol) && (::fabs(OldRadAccessData.zStep - NewRadAccessData.zStep) < RelStepTol)); if(OnlyMakeLargerRange) return RadResizeCore_OnlyLargerRange(OldRadAccessData, NewRadAccessData, RadResizeStruct, PolComp); + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeCore: RadResizeCore_OnlyLargerRange",&start); + char TreatPolCompX = ((PolComp == 0) || (PolComp == 'x')); char TreatPolCompZ = ((PolComp == 0) || (PolComp == 'z')); @@ -2466,14 +2762,23 @@ int srTGenOptElem::RadResizeCore(srTSRWRadStructAccessData& OldRadAccessData, sr bool OrigWfrQuadTermCanBeTreatedAtResizeX = OldRadAccessData.WfrQuadTermCanBeTreatedAtResizeX; bool OrigWfrQuadTermCanBeTreatedAtResizeZ = OldRadAccessData.WfrQuadTermCanBeTreatedAtResizeZ; + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeCore: init variables 1",&start); + //if((!RadResizeStruct.DoNotTreatSpherTerm) && WaveFrontTermCanBeTreated(OldRadAccessData)) if((!RadResizeStruct.doNotTreatSpherTerm()) && WaveFrontTermCanBeTreated(OldRadAccessData)) //OC090311 { + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeCore: doNotTreatSpherTerm+WaveFrontTermCanBeTreated",&start); + NewRadAccessData.WfrQuadTermCanBeTreatedAtResizeX = OldRadAccessData.WfrQuadTermCanBeTreatedAtResizeX; NewRadAccessData.WfrQuadTermCanBeTreatedAtResizeZ = OldRadAccessData.WfrQuadTermCanBeTreatedAtResizeZ; TreatStronglyOscillatingTerm(OldRadAccessData, 'r', PolComp); + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeCore: TreatStronglyOscillatingTerm 1",&start); + NewRadAccessData.wfrReffX = OldRadAccessData.wfrReffX; NewRadAccessData.wfrReffZ = OldRadAccessData.wfrReffZ; @@ -2487,11 +2792,11 @@ int srTGenOptElem::RadResizeCore(srTSRWRadStructAccessData& OldRadAccessData, sr int nx_mi_2Old = nx_mi_1Old - 1; int nz_mi_2Old = nz_mi_1Old - 1; - srTInterpolAux01 InterpolAux01; - - srTInterpolAux02 InterpolAux02[4], InterpolAux02I[2]; - srTInterpolAuxF AuxF[4], AuxFI[2]; - int ixStOld, izStOld, ixStOldPrev = -1000, izStOldPrev = -1000; + //OC31102018: moved by SY at parallelizing SRW via OpenMP + //srTInterpolAux01 InterpolAux01; + //srTInterpolAux02 InterpolAux02[4], InterpolAux02I[2]; + //srTInterpolAuxF AuxF[4], AuxFI[2]; + //int ixStOld, izStOld, ixStOldPrev = -1000, izStOldPrev = -1000; float *pEX0_New = 0, *pEZ0_New = 0; if(TreatPolCompX) pEX0_New = NewRadAccessData.pBaseRadX; @@ -2507,19 +2812,38 @@ int srTGenOptElem::RadResizeCore(srTSRWRadStructAccessData& OldRadAccessData, sr long long PerX_Old = PerX_New; long long PerZ_Old = PerX_Old*OldRadAccessData.nx; - float BufF[4], BufFI[2]; - char UseLowOrderInterp_PolCompX, UseLowOrderInterp_PolCompZ; + //OC31102018: moved by SY at OpenMP parallelization + //float BufF[4], BufFI[2]; + //char UseLowOrderInterp_PolCompX, UseLowOrderInterp_PolCompZ; + + //Added by SY (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":RadResizeCore: init variables",&start); int result = 0; + +#ifdef _WITH_OMP //OC31102018: added by SY at parallelizing SRW via OpenMP + #pragma omp parallel for +#endif + for(int ie=0; ie + struct SRWLStructOpticsTransmission; typedef struct SRWLStructOpticsTransmission SRWLOptT; diff --git a/cpp/src/core/sropthck.cpp b/cpp/src/core/sropthck.cpp index cc98d97b..60e52a43 100644 --- a/cpp/src/core/sropthck.cpp +++ b/cpp/src/core/sropthck.cpp @@ -87,46 +87,56 @@ srTMirror::srTMirror(const SRWLOptMir& srwlMir) m_extAlongOptAxIn = srwlMir.extIn; m_extAlongOptAxOut = srwlMir.extOut; - m_reflData.pData = (char*)srwlMir.arRefl; - m_reflData.DataType[0] = 'c'; - m_reflData.DataType[1] = 'd'; //? - m_reflData.AmOfDims = 3; - m_reflData.DimSizes[0] = srwlMir.reflNumPhEn; - m_reflData.DimSizes[1] = srwlMir.reflNumAng; - m_reflData.DimSizes[2] = srwlMir.reflNumComp; - m_reflData.DimStartValues[0] = - m_reflData.DimStartValues[1] = srwlMir.reflAngStart; - m_reflData.DimStartValues[2] = 1; - - if(strcmp(srwlMir.reflPhEnScaleType, "lin\0") == 0) + m_reflData.pData = 0; //OC12082018 + if(srwlMir.arRefl != 0) { - strcpy(m_reflData.DimScales[0], "lin\0"); - m_reflData.DimSteps[0] = srwlMir.reflPhEnFin - srwlMir.reflPhEnStart; - } - else if(strcmp(srwlMir.reflPhEnScaleType, "log\0") == 0) - { - strcpy(m_reflData.DimScales[0], "log\0"); - m_reflData.DimSteps[0] = log10(srwlMir.reflPhEnFin) - log10(srwlMir.reflPhEnStart); - } - if(srwlMir.reflNumPhEn > 1) m_reflData.DimSteps[0] /= (srwlMir.reflNumPhEn - 1); - if(strcmp(srwlMir.reflAngScaleType, "lin\0") == 0) - { - strcpy(m_reflData.DimScales[1], "lin\0"); - m_reflData.DimSteps[1] = srwlMir.reflAngFin - srwlMir.reflAngStart; - } - else if(strcmp(srwlMir.reflAngScaleType, "log\0") == 0) - { - strcpy(m_reflData.DimScales[1], "log\0"); - m_reflData.DimSteps[1] = log10(srwlMir.reflAngFin) - log10(srwlMir.reflAngStart); - } - if(srwlMir.reflNumAng > 1) m_reflData.DimSteps[1] /= (srwlMir.reflNumAng - 1); + m_reflData.pData = (char*)srwlMir.arRefl; + m_reflData.DataType[0] = 'c'; + m_reflData.DataType[1] = 'd'; //? + m_reflData.AmOfDims = 3; + m_reflData.DimSizes[0] = srwlMir.reflNumPhEn; + m_reflData.DimSizes[1] = srwlMir.reflNumAng; + m_reflData.DimSizes[2] = srwlMir.reflNumComp; + m_reflData.DimStartValues[0] = srwlMir.reflPhEnStart; + m_reflData.DimStartValues[1] = srwlMir.reflAngStart; + m_reflData.DimStartValues[2] = 1; + + m_reflData.DimSteps[0] = 0; + //if(srwlMir.reflNumPhEn > 1) m_reflData.DimSteps[0] = (srwlMir.reflPhEnFin - srwlMir.reflPhEnStart)/(srwlMir.reflNumPhEn - 1); + m_reflData.DimSteps[1] = 0; + //if(srwlMir.reflNumAng > 1) m_reflData.DimSteps[1] = (srwlMir.reflAngFin - srwlMir.reflAngStart)/(srwlMir.reflNumAng - 1); + m_reflData.DimSteps[2] = 0; - strcpy(m_reflData.DimUnits[0], "eV"); - strcpy(m_reflData.DimUnits[1], "rad"); - m_reflData.DimUnits[2][0] = '\0'; - m_reflData.DataUnits[0] = '\0'; - m_reflData.DataName[0] = '\0'; - m_reflData.hState = 1; + if(strcmp(srwlMir.reflPhEnScaleType, "lin\0") == 0) + { + strcpy(m_reflData.DimScales[0], "lin\0"); + if(srwlMir.reflNumPhEn > 1) m_reflData.DimSteps[0] = (srwlMir.reflPhEnFin - srwlMir.reflPhEnStart)/(srwlMir.reflNumPhEn - 1); + } + else if(strcmp(srwlMir.reflPhEnScaleType, "log\0") == 0) + { + strcpy(m_reflData.DimScales[0], "log\0"); + if(srwlMir.reflNumPhEn > 1) m_reflData.DimSteps[0] = (log10(srwlMir.reflPhEnFin) - log10(srwlMir.reflPhEnStart))/(srwlMir.reflNumPhEn - 1); + } + //if(srwlMir.reflNumPhEn > 1) m_reflData.DimSteps[0] /= (srwlMir.reflNumPhEn - 1); + if(strcmp(srwlMir.reflAngScaleType, "lin\0") == 0) + { + strcpy(m_reflData.DimScales[1], "lin\0"); + if(srwlMir.reflNumAng > 1) m_reflData.DimSteps[1] = (srwlMir.reflAngFin - srwlMir.reflAngStart)/(srwlMir.reflNumAng - 1); + } + else if(strcmp(srwlMir.reflAngScaleType, "log\0") == 0) + { + strcpy(m_reflData.DimScales[1], "log\0"); + if(srwlMir.reflNumAng > 1) m_reflData.DimSteps[1] = (log10(srwlMir.reflAngFin) - log10(srwlMir.reflAngStart))/(srwlMir.reflNumAng - 1); + } + //if(srwlMir.reflNumAng > 1) m_reflData.DimSteps[1] /= (srwlMir.reflNumAng - 1); + + strcpy(m_reflData.DimUnits[0], "eV"); + strcpy(m_reflData.DimUnits[1], "rad"); + m_reflData.DimUnits[2][0] = '\0'; + m_reflData.DataUnits[0] = '\0'; + m_reflData.DataName[0] = '\0'; + m_reflData.hState = 1; + } m_vCenNorm.x = srwlMir.nvx; //central normal in the frame of incident beam m_vCenNorm.y = srwlMir.nvy; @@ -523,8 +533,9 @@ void srTMirror::FindElemExtentsAlongOptAxes(gmTrans& trfMir, TVector3d& vCenNorm //************************************************************************* +int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax, double dxMax, double dzMax) //OC20082018 +//int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax) //int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax) -int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax) {//OC18032016 if((pWfr == 0) || (arRayTrCoord == 0) || ((arEX == 0) && (arEZ == 0))) return FAILED_INTERPOL_ELEC_FLD; //if((pWfr == 0) || (arRayTrCoord == 0) || (arOptPathDif == 0) || ((arEX == 0) && (arEZ == 0))) return FAILED_INTERPOL_ELEC_FLD; @@ -540,10 +551,6 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a pWfr->pBaseRadX = arEX; pWfr->pBaseRadZ = arEZ; - //testoc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - //TreatStronglyOscillatingTerm(*pWfr, 'r'); - //end testoc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - //if(!((fabs(pWfr->RobsX + 0.99) < 0.1) && (fabs(pWfr->RobsZ + 0.99) < 0.1))) //{//OCTEST @@ -574,7 +581,6 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a long long nTot = PerZ*(pWfr->nz); //OCTEST - //if((fabs(pWfr->RobsX + 20.596) < 0.1) && (fabs(pWfr->RobsZ + 18.079) < 0.1)) //if(fabs(pWfr->RobsZ + 18.079) < 0.1) //{ //float *t_arEX = arEX, *t_arEZ = arEZ; @@ -592,7 +598,16 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a double arReEx[4], arImEx[4], arReEz[4], arImEz[4], arIx[4], arIz[4]; //Aux. arrays to be used for interpolation double dx, dz, ReE, ImE; - const int maxSearchRad = 3; //To tune + //const int maxSearchRad = 3; //To tune + //OC11082018 (the above didn't allow to find indCloseRayTrCoord for the case of Grating in Example #12) + int maxSearchRad = 20; //10; //100; //1000; //To tune + int halfNx_mi_2 = (pWfr->nx - 1) >> 1; + if(maxSearchRad > halfNx_mi_2) maxSearchRad = halfNx_mi_2; + int halfNz_mi_2 = (pWfr->nz - 1) >> 1; + if(maxSearchRad > halfNz_mi_2) maxSearchRad = halfNz_mi_2; + + const double interpSafeFact = 2.5; //OC20082018 + long ixMin = (long)((xMin - (pWfr->xStart))/(pWfr->xStep)); long ixMax = (long)((xMax - (pWfr->xStart))/(pWfr->xStep)); long izMin = (long)((zMin - (pWfr->zStart))/(pWfr->zStep)); @@ -601,11 +616,15 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a double z = pWfr->zStart; for(long iz=0; iz<(pWfr->nz); iz++) { + bool pointIsWithinVertLim = (zMin < z) && (z < zMax); + //long izHalfPerZ = iz*HalfPerZ; long long izHalfPerZ = iz*HalfPerZ; double x = pWfr->xStart; for(long ix=0; ix<(pWfr->nx); ix++) { + bool pointIsWithinTransvLim = (xMin < x) && (x < xMax) && pointIsWithinVertLim; + //long izHalfPerZ_p_ixHalfPerX = izHalfPerZ + ix*HalfPerX; long long izHalfPerZ_p_ixHalfPerX = izHalfPerZ + ix*HalfPerX; for(long ie=0; ie<(pWfr->ne); ie++) @@ -613,113 +632,184 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a *t_ExRes = 0.; *(t_ExRes+1) = 0.; *t_EzRes = 0.; *(t_EzRes+1) = 0.; - //OCTEST - //if(fabs(pWfr->RobsZ + 18.079) < 0.1) - //{ - // //if((ix == 1124) && (iz == 408)) - // //if((ix == 1585) && (iz == 198)) - // if((ix == 231) && (iz == 189)) - // { - // int aha = 1; - // } - //} - //END OCTEST + //OCTEST + //if(m_isGrating && (ix==207) && (iz==1425)) + //if(m_isGrating && (ix==287) && (iz==1427)) + //{ + // int aha = 1; + //} + //END OCTEST //long indCloseRayTrCoord = arIndRayTrCoord[izHalfPerZ_p_ixHalfPerX + ie]; long long indCloseRayTrCoord = arIndRayTrCoord[izHalfPerZ_p_ixHalfPerX + ie]; - if((indCloseRayTrCoord < 0) && ((xMin < x) && (x < xMax) && (zMin < z) && (z < zMax))) + + if((indCloseRayTrCoord < 0) && pointIsWithinTransvLim) //OC19082018 + //if((indCloseRayTrCoord < 0) && ((xMin < x) && (x < xMax) && (zMin < z) && (z < zMax))) {//Try to find nearest non-negative value of the index bool thereAreDataXL=false, thereAreDataXU=false; bool thereAreDataYL=false, thereAreDataYU=false; - //long indFirstFound=-1; long long indFirstFound=-1; + for(int ic=1; ic<=maxSearchRad; ic++) { int two_ic = ic << 1; - for(int icz=-ic; icz<=ic; icz+=two_ic) - { - long jz = iz + icz; - if((jz < izMin) || (jz > izMax)) continue; - - //long jzHalfPerZ_p_ie = jz*HalfPerZ + ie; - long long jzHalfPerZ_p_ie = jz*HalfPerZ + ie; - for(int icx=-ic; icx<=ic; icx++) + if((indFirstFound < 0) || (!thereAreDataYL) || (!thereAreDataYU)) //OC12082018 + //if(indFirstFound < 0) //OC12082018 + { + for(int icz=-ic; icz<=ic; icz+=two_ic) { - long jx = ix + icx; - if((jx < ixMin) || (jx > ixMax)) continue; - - //long testOfst = jzHalfPerZ_p_ie + jx*HalfPerX; - long long testOfst = jzHalfPerZ_p_ie + jx*HalfPerX; - //long testOfst = jzHalfPerZ_p_ie + ix*HalfPerX; - if((testOfst < 0) || (testOfst >= half_nTot)) continue; + long jz = iz + icz; + if((jz < izMin) || (jz > izMax)) continue; - //indCloseRayTrCoord = arIndRayTrCoord[testOfst]; - //if(indCloseRayTrCoord >= 0) - //long indCur = arIndRayTrCoord[testOfst]; - long long indCur = arIndRayTrCoord[testOfst]; - if(indCur >= 0) + //long jzHalfPerZ_p_ie = jz*HalfPerZ + ie; + long long jzHalfPerZ_p_ie = jz*HalfPerZ + ie; + for(int icx=-ic; icx<=ic; icx++) { - if(indFirstFound < 0) indFirstFound = indCur; + //long jx = ix + icx; + long icxCor = icx + ic; //OC21082018 + if(icxCor > 0) + { + int icxCor_d_2 = icxCor >> 1; + if((icxCor_d_2 << 1) != icxCor) icxCor = -(icxCor_d_2 + 1); + else icxCor = icxCor_d_2; + } + long jx = ix + icxCor; //OC21082018 + if((jx < ixMin) || (jx > ixMax)) continue; + + //long testOfst = jzHalfPerZ_p_ie + jx*HalfPerX; + long long testOfst = jzHalfPerZ_p_ie + jx*HalfPerX; + //long testOfst = jzHalfPerZ_p_ie + ix*HalfPerX; + if((testOfst < 0) || (testOfst >= half_nTot)) continue; + + //indCloseRayTrCoord = arIndRayTrCoord[testOfst]; + //if(indCloseRayTrCoord >= 0) + //long indCur = arIndRayTrCoord[testOfst]; + long long indCur = arIndRayTrCoord[testOfst]; + if(indCur >= 0) + { + if(indFirstFound < 0) + { + indFirstFound = indCur; + } + //else + //{//OC12082018 + // if(icz >= 0) thereAreDataYU = true; + //} + //if(icz < 0) thereAreDataYL = true; - if(icz < 0) thereAreDataYL = true; - else thereAreDataYU = true; + if(icz < 0) thereAreDataYL = true; + else thereAreDataYU = true; + break; + } + } + //if(indCloseRayTrCoord >= 0) break; + //OC11082018 + if((indFirstFound >= 0) && thereAreDataYL && thereAreDataYU) + { break; } + //if(indFirstFound >= 0) + //{ + // //indCloseRayTrCoord = indFirstFound; + // break; + //} } - //if(indCloseRayTrCoord >= 0) break; } //if(indCloseRayTrCoord >= 0) break; if((indFirstFound >= 0) && thereAreDataXL && thereAreDataXU && thereAreDataYL && thereAreDataYU) + //OC12082018: problems with Example #12 showed "negative" impact of thereAreDataXL, thereAreDataXU, thereAreDataYL, thereAreDataYU + //if(indFirstFound >= 0) { indCloseRayTrCoord = indFirstFound; break; } - for(int icx=-ic; icx<=ic; icx+=two_ic) + if((indFirstFound < 0) || (!thereAreDataXL) || (!thereAreDataXU)) //OC12082018 + //if(indFirstFound < 0) //OC12082018 { - long jx = ix + icx; - if((jx < ixMin) || (jx > ixMax)) continue; - - //long jxHalfPerX_p_ie = jx*HalfPerX + ie; - long long jxHalfPerX_p_ie = jx*HalfPerX + ie; - for(int icz=-ic+1; icz<=(ic-1); icz++) + for(int icx=-ic; icx<=ic; icx+=two_ic) { - long jz = iz + icz; - if((jz < izMin) || (jz > izMax)) continue; + long jx = ix + icx; + if((jx < ixMin) || (jx > ixMax)) continue; - //long testOfst = jxHalfPerX_p_ie + jz*HalfPerZ; - long long testOfst = jxHalfPerX_p_ie + jz*HalfPerZ; - //long testOfst = jxHalfPerX_p_ie + iz*HalfPerZ; - if((testOfst < 0) || (testOfst >= half_nTot)) continue; + //long jxHalfPerX_p_ie = jx*HalfPerX + ie; + long long jxHalfPerX_p_ie = jx*HalfPerX + ie; + for(int icz=-ic+1; icz<=(ic-1); icz++) + { + //long jz = iz + icz; + long iczCor = icz + ic - 1; //OC21082018 + if(iczCor > 0) + { + int iczCor_d_2 = iczCor >> 1; + if((iczCor_d_2 << 1) != iczCor) iczCor = -(iczCor_d_2 + 1); + else iczCor = iczCor_d_2; + } + long jz = iz + iczCor; //OC21082018 + if((jz < izMin) || (jz > izMax)) continue; + + //long testOfst = jxHalfPerX_p_ie + jz*HalfPerZ; + long long testOfst = jxHalfPerX_p_ie + jz*HalfPerZ; + //long testOfst = jxHalfPerX_p_ie + iz*HalfPerZ; + if((testOfst < 0) || (testOfst >= half_nTot)) continue; + + //indCloseRayTrCoord = arIndRayTrCoord[testOfst]; + //if(indCloseRayTrCoord >= 0) break; + //long indCur = arIndRayTrCoord[testOfst]; + long long indCur = arIndRayTrCoord[testOfst]; + if(indCur >= 0) + { + if(indFirstFound < 0) + { + indFirstFound = indCur; + } + //else + //{//OC12082018 + // if(icx >= 0) thereAreDataXU = true; + //} + //if(icx < 0) thereAreDataXL = true; - //indCloseRayTrCoord = arIndRayTrCoord[testOfst]; + if(icx < 0) thereAreDataXL = true; + else thereAreDataXU = true; + break; + } + } //if(indCloseRayTrCoord >= 0) break; - //long indCur = arIndRayTrCoord[testOfst]; - long long indCur = arIndRayTrCoord[testOfst]; - if(indCur >= 0) + //OC11082018 + if((indFirstFound >= 0) && thereAreDataXL && thereAreDataXU) { - if(indFirstFound < 0) indFirstFound = indCur; - - if(icx < 0) thereAreDataXL = true; - else thereAreDataXU = true; break; } + //if(indFirstFound >= 0) + //{ + // //indCloseRayTrCoord = indFirstFound; + // break; + //} } - //if(indCloseRayTrCoord >= 0) break; } + //if(indCloseRayTrCoord >= 0) break; if((indFirstFound >= 0) && thereAreDataXL && thereAreDataXU && thereAreDataYL && thereAreDataYU) + //OC12082018: problems with Example #12 showed "negative" impact of thereAreDataXL, thereAreDataXU, thereAreDataYL, thereAreDataYU + //if(indFirstFound >= 0) { indCloseRayTrCoord = indFirstFound; break; } + + //if(((fabs(ic*(pWfr->xStep)) > dxMax*interpSafeFact) && ((!thereAreDataXL) || (!thereAreDataXU))) || + // ((fabs(ic*(pWfr->zStep)) > dzMax*interpSafeFact) && ((!thereAreDataYL) || (!thereAreDataYU)))) //OC20082018 + if((indFirstFound < 0) && ((fabs(ic*(pWfr->xStep)) > dxMax*interpSafeFact) || (fabs(ic*(pWfr->zStep)) > dzMax*interpSafeFact))) //OC20082018 + { + break; //Stop search for a good point over a too large range + } } } //if(indCloseRayTrCoord >= 0) - if((indCloseRayTrCoord >= 0) && ((xMin <= x) && (x <= xMax) && (zMin <= z) && (z <= zMax))) //OC03072017 (trying to avoid having an aventual "nan" in the resulting field data) + //if((indCloseRayTrCoord >= 0) && ((xMin <= x) && (x <= xMax) && (zMin <= z) && (z <= zMax))) //OC03072017 (trying to avoid having an aventual "nan" in the resulting field data) + if((indCloseRayTrCoord >= 0) && pointIsWithinTransvLim) //OC19082018 { double *pRayTrCoord = arRayTrCoord + indCloseRayTrCoord; double xCloseRayTr = *pRayTrCoord; @@ -1008,7 +1098,7 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a double resIx = CGenMathInterp::Interp2dBiLinVar(relX, relZ, arRelCoordXZ, arIx); if(resIx <= 0) { - resReEx = 0.; resImEx *= 0.; + resReEx = 0.; resImEx = 0.; } else { @@ -1034,7 +1124,7 @@ int srTMirror::WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* a double resIz = CGenMathInterp::Interp2dBiLinVar(relX, relZ, arRelCoordXZ, arIz); if(resIz <= 0) { - resReEz = 0.; resImEz *= 0.; + resReEz = 0.; resImEz = 0.; } else { @@ -1962,6 +2052,12 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* double EsigRe, EsigIm, EpiRe, EpiIm; double grMult; + double dxOutMin = 1.e+23*(pRadAccessData->nx)*(pRadAccessData->xStep); //OC20082018 + double dxOutMax = 0.; + double dyOutMin = 1.e+23*(pRadAccessData->nz)*(pRadAccessData->zStep); + double dyOutMax = 0.; + double xRelOutPrev = 1.e+23, yRelOutPrev = 1.e+23; + for(long ie=0; iene; ie++) { double TwoPi_d_LambdaM = ePh*5.067730652e+06; @@ -1969,6 +2065,7 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* if(m_isGrating) grMult = m_grM/(806554.3835*ePh); + bool coordOutFoundY = false; y = pRadAccessData->zStart; for(long iy=0; iynz; iy++) { @@ -1987,6 +2084,7 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* //bool firstHitForThisY = true; //OC19032016 + bool coordOutFoundX = false; x = pRadAccessData->xStart; for(long ix=0; ixnx; ix++) { @@ -2009,16 +2107,6 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* //*pAuxRayTrCoordX = (float)(-1.E+23); *pAuxRayTrCoordY = (float)(-1.E+23); *pAuxRayTrCoordX = -1.E+23; *pAuxRayTrCoordY = -1.E+23; - //OCTEST - //if(fabs(pRadAccessData->RobsZ + 18.079) < 0.1) - //{ - //if((ix == 1124) && (iz == 408)) - //{ - //int aha = 1; - //} - //} - //END OCTEST - //long *pAuxIndRayTrCoord = arAuxIndRayTrCoord + iyHalfPerY_p_ie + ix*HalfPerX; //*pAuxIndRayTrCoord = -1; @@ -2214,6 +2302,23 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* *pAuxRayTrCoordX = xRelOut; *pAuxRayTrCoordY = yRelOut; + if(coordOutFoundX) //OC20082018 + { + double dxOut = fabs(xRelOut - xRelOutPrev); + if(dxOutMin > dxOut) dxOutMin = dxOut; + else if(dxOutMax < dxOut) dxOutMax = dxOut; + } + if(coordOutFoundY) //OC20082018 + { + double dyOut = fabs(yRelOut - yRelOutPrev); + if(dyOutMin > dyOut) dyOutMin = dyOut; + else if(dyOutMax < dyOut) dyOutMax = dyOut; + } + xRelOutPrev = xRelOut; + yRelOutPrev = yRelOut; + coordOutFoundX = true; + coordOutFoundY = true; + //OCTEST //if(y > 0) //if(y > 0.0043) @@ -2261,22 +2366,12 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* arAuxIndRayTrCoord[ofstTrfCoord] = ofstToSet; - //OCTEST - //if(fabs(pRadAccessData->RobsZ + 18.079) < 0.1) - //{ - //if((ix == 1124) && (iz == 408)) + //OCTEST + //if(m_isGrating && (ix==207)) //{ - //int aha = 1; + // int aha = 1; //} - //} - //END OCTEST - - //double angE2 = tgAngX*tgAngX + tgAngY*tgAngY; - //double angFact = 1. + angE2*(0.5 + angE2*((5./24.) + (61./720.)*angE2)); - //////double angFact = 1. + angE2*0.5; - ////double optPathDif = optPath - (m_extAlongOptAxIn + m_extAlongOptAxOut)*angFact; //L/cos(alpha) - //////double optPathDif = optPath - (m_extAlongOptAxIn + m_extAlongOptAxOut); //L/cos(alpha) - //double optPathDif = optPath; + //END OCTEST //last commented: //double phShift = TwoPi_d_LambdaM*optPathDif; //to check sign! @@ -2311,7 +2406,7 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* *pEyReRes = (float)NewEzRe; *pEyImRes = (float)NewEzIm; } - //test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + //OCTEST //double Pi_d_Lambda_m = ePh*2.533840802E+06; //double xRel = x - TransvCenPoint.x, zRel = y - TransvCenPoint.y; @@ -2323,7 +2418,7 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* //float NewEzRe = (*pEzRe)*cosPh - (*pEzIm)*sinPh; //float NewEzIm = (*pEzRe)*sinPh + (*pEzIm)*cosPh; //*pEyReRes = NewEzRe; *pEyImRes = NewEzIm; - //end test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + //END OCTEST //*pExRe = phShift; *pExIm = 0; //*pEzRe = phShift; *pEzIm = 0; @@ -2421,9 +2516,10 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* //*pExReRes = xRelOut; *pExImRes = yRelOut; //*pEyReRes = xRelOut; *pEyImRes = yRelOut; //} - //end OCTEST!!!!!!!!!!!!!!!!!!!!! + //END OCTEST!!!!!!!!!!!!!!!!!!!!! } } + //firstHitForThisY = false; //OC19032016 } } @@ -2439,9 +2535,12 @@ int srTMirror::PropagateRadiationSimple_LocRayTracing(srTSRWRadStructAccessData* //if(res = WfrInterpolOnOrigGrid(pRadAccessData, arAuxRayTrCoord, arAuxEX, arAuxEY, xRelOutMin, xRelOutMax, yRelOutMin, yRelOutMax)) return res; //OCTEST //if(fabs(pRadAccessData->RobsZ + 18.079) > 0.1) + //if(!m_isGrating) //{//OCTEST - if(res = WfrInterpolOnOrigGrid2(pRadAccessData, arAuxRayTrCoord, arAuxIndRayTrCoord, arAuxEX, arAuxEY, xRelOutMin, xRelOutMax, yRelOutMin, yRelOutMax)) return res; + //if(res = WfrInterpolOnOrigGrid2(pRadAccessData, arAuxRayTrCoord, arAuxIndRayTrCoord, arAuxEX, arAuxEY, xRelOutMin, xRelOutMax, yRelOutMin, yRelOutMax)) return res; + //OC20082018 + if(res = WfrInterpolOnOrigGrid2(pRadAccessData, arAuxRayTrCoord, arAuxIndRayTrCoord, arAuxEX, arAuxEY, xRelOutMin, xRelOutMax, yRelOutMin, yRelOutMax, dxOutMax, dyOutMax)) return res; //} //else diff --git a/cpp/src/core/sropthck.h b/cpp/src/core/sropthck.h index 00594bb7..fa312394 100644 --- a/cpp/src/core/sropthck.h +++ b/cpp/src/core/sropthck.h @@ -19,6 +19,9 @@ #include "gmmeth.h" #include "srwlib.h" +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +//#include + //************************************************************************* //class srTOptThickElem : public srTFocusingElem { @@ -91,7 +94,8 @@ class srTMirror : public srTFocusingElem { //int WfrInterpolOnOrigGrid(srTSRWRadStructAccessData* pWfr, float* arRayTrCoord, float* arEX, float* arEY, float xRelOutMin, float xRelOutMax, float yRelOutMin, float yRelOutMax); int WfrInterpolOnOrigGrid(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, float* arEX, float* arEY, double xRelOutMin, double xRelOutMax, double yRelOutMin, double yRelOutMax); //int WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax); - int WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax); + //int WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax); + int WfrInterpolOnOrigGrid2(srTSRWRadStructAccessData* pWfr, double* arRayTrCoord, long long* arIndRayTrCoord, float* arEX, float* arEZ, double xMin, double xMax, double zMin, double zMax, double dxMax, double dzMax); //OC20082018 virtual void FindSurfNormalInLocFrame(double x, double y, TVector3d& vN) {} virtual double SurfHeightInLocFrame(double x, double y) { return 0;} @@ -513,11 +517,11 @@ class srTMirrorEllipsoid : public srTMirror { //double t0 = (m_p < m_q)? -(a + ax_ay_az*sqrt(argRoot))/b : -(a - ax_ay_az*sqrt(argRoot))/b; //to check //OC06072017: it looks like the second option of t0 should be used at any m_p, m_q - double testTerm = ax_ay_az*sqrt(argRoot); //OCTEST - if(fabs(a - testTerm) < fabs(testTerm)*1e-13) - { - int aha = 1; - } + //double testTerm = ax_ay_az*sqrt(argRoot); //OCTEST + //if(fabs(a - testTerm) < fabs(testTerm)*1e-13) + //{ + // int aha = 1; + //} double t0 = -(a - ax_ay_az*sqrt(argRoot))/b; //OC06072017 diff --git a/cpp/src/core/srradmnp.cpp b/cpp/src/core/srradmnp.cpp index aa184d0e..15c4327c 100644 --- a/cpp/src/core/srradmnp.cpp +++ b/cpp/src/core/srradmnp.cpp @@ -14,6 +14,7 @@ #include "srradmnp.h" #include "gmfft.h" #include "gmmeth.h" +//#include "gminterp.h" #include "srerror.h" //DEBUG @@ -681,6 +682,320 @@ int srTRadGenManip::ExtractSingleElecIntensity3D(srTRadExtract& RadExtract) //************************************************************************* +int srTRadGenManip::ExtractSingleElecMutualIntensityVsX(srTRadExtract& RadExtract) +{//OC06092018 + int res = 0; + int PolCom = RadExtract.PolarizCompon; + int Int_or_ReE = RadExtract.Int_or_Phase; + srTSRWRadStructAccessData& RadAccessData = *((srTSRWRadStructAccessData*)(hRadAccessData.ptr())); + + float *pMI = RadExtract.pExtractedData; + float *pEx0 = RadAccessData.pBaseRadX; + float *pEz0 = RadAccessData.pBaseRadZ; + + long long PerX = RadAccessData.ne << 1; + long long PerZ = PerX*RadAccessData.nx; + + long ie0=0, ie1=0, iz0=0, iz1=0; + double InvStepRelArg1, InvStepRelArg2; + + SetupIntCoord('z', RadExtract.z, iz0, iz1, InvStepRelArg2); + SetupIntCoord('e', RadExtract.ePh, ie0, ie1, InvStepRelArg1); + + const double tolRelArg = 1.e-08; + bool NeedInterp = true; + if(((iz0 == iz1) || (fabs(InvStepRelArg2) < tolRelArg)) && + ((ie0 == ie1) || (fabs(InvStepRelArg1) < tolRelArg))) NeedInterp = false; + + long Two_ie0 = ie0 << 1, Two_ie1 = ie1 << 1; + long long iz0PerZ = iz0*PerZ, iz1PerZ = iz1*PerZ; + float *pEx_StartForX_iz0 = pEx0 + iz0PerZ, *pEx_StartForX_iz1 = pEx0 + iz1PerZ; + float *pEz_StartForX_iz0 = pEz0 + iz0PerZ, *pEz_StartForX_iz1 = pEz0 + iz1PerZ; + float *pEx_StartForE_iz0, *pEx_StartForE_iz1; + float *pEz_StartForE_iz0, *pEz_StartForE_iz1; + + //First RadAccessData.nx values are the "normal" intensity (real diagonal elements of mutual intensity) + long nx = RadAccessData.nx; + long long ixPerX = 0; + for(long ix=0; ixAmOfDims != 1) || (pwI1->pWaveData == 0) || (pwI2->AmOfDims != 2) || (pwI2->pWaveData == 0)) throw SRWL_INCORRECT_PARAM_FOR_INT_PROC; + + bool calcAvg = ((char)arPar[0] == 1); + char meth = (char)arPar[1]; + + int nPhMax = 0; + double relPrec = 1.e-03; + if(meth == 1) + { + nPhMax = (int)arPar[2]; + if(nPhMax <= 0) throw SRWL_INCORRECT_PARAM_FOR_INT_PROC; + } + else if(meth == 2) relPrec = arPar[2]; + else throw SRWL_INCORRECT_PARAM_FOR_INT_PROC; + + char ordInterp = (char)arPar[3]; + double phMin = arPar[4]; + double phMax = arPar[5]; + double x0 = arPar[6]; + double y0 = arPar[7]; + + const double twoPi = 2*3.141592653589793; + if(phMin == phMax) phMax = phMin + twoPi; + double phRange = phMax - phMin; + + float *pfI1=0, *pfI2=0; + double *pdI1=0, *pdI2=0; + char typeI1 = *(pwI1->WaveType), typeI2 = *(pwI2->WaveType); + + if(typeI1 == 'f') pfI1 = (float*)(pwI1->pWaveData); + else if(typeI1 == 'd') pdI1 = (double*)(pwI1->pWaveData); + else throw SRWL_INCORRECT_PARAM_FOR_INT_PROC; + + float *tfI1 = pfI1; + double *tdI1 = pdI1; + + if(typeI2 == 'f') pfI2 = (float*)(pwI2->pWaveData); + else if(typeI2 == 'd') pdI2 = (double*)(pwI2->pWaveData); + else throw SRWL_INCORRECT_PARAM_FOR_INT_PROC; + + double xMin = *(pwI2->DimStartValues); + double xStep = *(pwI2->DimSteps); + long nx = *(pwI2->DimSizes); + + double yMin = *((pwI2->DimStartValues) + 1); + double yStep = *((pwI2->DimSteps) + 1); + long ny = *((pwI2->DimSizes) + 1); + + double *arFuncForAzimInt=0; + if(nPhMax > 0) arFuncForAzimInt = new double[nPhMax]; + + long nr = *(pwI1->DimSizes); + double rStep = *(pwI1->DimSteps); + double r = *(pwI1->DimStartValues); + double rMax = r + rStep*(nr - 1); + + double tolPhMeth2=0; + double dFdPh1=0, dFdPh2=0; + srTAuxInt2DIntegOverAzim auxStruct; + if(meth == 2) + { + auxStruct.x0 = x0; + auxStruct.y0 = y0; + auxStruct.xMin = xMin; + auxStruct.xStep = xStep; + auxStruct.nx = nx; + auxStruct.yMin = yMin; + auxStruct.yStep = yStep; + auxStruct.ny = ny; + auxStruct.pfI2D = pfI2; + auxStruct.pdI2D = pdI2; + auxStruct.ordInterp = ordInterp; + + tolPhMeth2 = ::fabs(phRange*relPrec); + if(::fabs(::fabs(phRange) - twoPi) < tolPhMeth2) tolPhMeth2 = 0; //meaning that calculation of edge derivatives vs phi is not necessary + } + + for(int ir=0; ir 0) curIntOverPh = CGenMathMeth::Integ1D_Func(&(srTRadGenManip::IntCylCrd), phMin, phMax, relPrec, (void*)(&auxStruct)); + else curIntOverPh = CGenMathMeth::Integ1D_FuncWithEdgeDer(&(srTRadGenManip::IntCylCrd), phMin, phMax, dFdPh1, dFdPh2, relPrec, (void*)(&auxStruct)); + } + } + + if(calcAvg) curIntOverPh /= phRange; + + if(pfI1) *(tfI1++) = (float)curIntOverPh; + else *(tdI1++) = curIntOverPh; + + r += rStep; + } + + if(arFuncForAzimInt != 0) delete[] arFuncForAzimInt; +} + +//************************************************************************* + void srTRadGenManip::ComponInteg(srTDataMD* pIntensOrigData, srTDataMD* pIntegParData, srTDataMD* pIntegResData) -{ +{ if((pIntensOrigData == 0) || (pIntegParData == 0) || (pIntegResData == 0)) throw INCORRECT_PARAMS_WFR_COMPON_INTEG; //{IntegType, eMin, eMax, xMin, xMax, zMin, zMax} diff --git a/cpp/src/core/srradmnp.h b/cpp/src/core/srradmnp.h index f334c5e4..c4cd521c 100644 --- a/cpp/src/core/srradmnp.h +++ b/cpp/src/core/srradmnp.h @@ -17,6 +17,7 @@ #include "sroptelm.h" #include "srstraux.h" #include "srerror.h" +#include "gminterp.h" #include @@ -26,6 +27,17 @@ extern srTIntVect gVectWarnNos; //************************************************************************* +struct srTAuxInt2DIntegOverAzim { + double x0, y0, r; + double xMin, xStep, yMin, yStep; + long nx, ny; + float *pfI2D; + double *pdI2D; + char ordInterp; +}; + +//************************************************************************* + class srTRadGenManip { // Various manipulations with computed Radiation bool EhOK, EvOK; //OC111111 @@ -54,6 +66,20 @@ class srTRadGenManip { } void ExtractRadiation(int PolarizCompon, int Int_or_Phase, int SectID, int TransvPres, double e, double x, double z, char* pData); + + void ExtractRadiationSRWL(char polar, char intType, char depType, char transvPres, double e, double x, double z, char* pData) //OC19082018 + { + //Re-defining intType + //from SRWL convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Flux; 3- Multi-Elec. Flux; 4- Single-Elec. Rad. Phase; 5- Re(E); 6- Im(E); 7- Time or Photon Energy Integrated Intensity + //to old SRW convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Rad. Phase; 3- Re(E); 4- Single-Elec. Flux; 5- Multi-Elec. Flux; 6- Im(E); 7- Time or Photon Energy Integrated Intensity + if(intType == 2) intType = 4; + else if(intType == 3) intType = 5; + else if(intType == 4) intType = 2; + else if(intType == 5) intType = 3; + + ExtractRadiation((int)polar, (int)intType, (int)depType, (int)transvPres, e, x, z, pData); + } + int ExtractRadiation(srTRadExtract& RadExtract, srTWaveAccessData& ExtractedWaveData) { int result; @@ -89,6 +115,24 @@ class srTRadGenManip { else return ExtractSingleElecIntensity3D(RadExtract); } + int ExtractSingleElecMutualIntensity(srTRadExtract& RadExtract) + {//OC06092018 + int PolCom = RadExtract.PolarizCompon; + int Int_or_ReE = RadExtract.Int_or_Phase; + //if((PolCom == 6) || (Int_or_ReE != 8)) return CAN_NOT_EXTRACT_MUT_INT; + if(Int_or_ReE != 8) return CAN_NOT_EXTRACT_MUT_INT; + + //if(RadExtract.PlotType == 0) return ExtractSingleElecMutualIntensityVsE(RadExtract); + //else if(RadExtract.PlotType == 1) return ExtractSingleElecMutualIntensityVsX(RadExtract); + if(RadExtract.PlotType == 1) return ExtractSingleElecMutualIntensityVsX(RadExtract); + else if(RadExtract.PlotType == 2) return ExtractSingleElecMutualIntensityVsZ(RadExtract); + else if(RadExtract.PlotType == 3) return ExtractSingleElecMutualIntensityVsXZ(RadExtract); + //else if(RadExtract.PlotType == 4) return ExtractSingleElecMutualIntensityVsEX(RadExtract); + //else if(RadExtract.PlotType == 5) return ExtractSingleElecMutualIntensityVsEZ(RadExtract); + //else return ExtractSingleElecMutualIntensityEXZ(RadExtract); + else return CAN_NOT_EXTRACT_MUT_INT; + } + int TryToMakePhaseContinuous(srTWaveAccessData& WaveData); void TryToMakePhaseContinuous1D(double* pOutPhase, long Np, long i0, float Phi0); @@ -99,6 +143,11 @@ class srTRadGenManip { int ExtractSingleElecIntensity2DvsEX(srTRadExtract&); int ExtractSingleElecIntensity2DvsEZ(srTRadExtract&); int ExtractSingleElecIntensity3D(srTRadExtract&); + + int ExtractSingleElecMutualIntensityVsX(srTRadExtract&); //OC06092018 + int ExtractSingleElecMutualIntensityVsZ(srTRadExtract&); + int ExtractSingleElecMutualIntensityVsXZ(srTRadExtract&); + int SetupExtractedWaveData(srTRadExtract&, srTWaveAccessData&); void SetupIntCoord(char, double, long&, long&, double&); @@ -259,6 +308,136 @@ class srTRadGenManip { else return (Im > 0.)? HalhPi : -HalhPi; } } + + int MutualIntensityComponentSimpleInterpol(float** ExPtrs, float** ExPtrsT, float** EzPtrs, float** EzPtrsT, double InvStepRelArg, int PolCom, float* pResMI) + {//OC12092018 + float MI0[2], MI1[2]; + int res = 0; + if(res = MutualIntensityComponent(*ExPtrs, *ExPtrsT, *EzPtrs, *EzPtrsT, PolCom, MI0)) return res; + if(res = MutualIntensityComponent(*(ExPtrs + 1), *(ExPtrsT + 1), *(EzPtrs + 1), *(EzPtrsT + 1), PolCom, MI1)) return res; + double MI0Re = *MI0, MI0Im = *(MI0 + 1); + double MI1Re = *MI1, MI1Im = *(MI1 + 1); + *pResMI = (float)((MI1Re - MI0Re)*InvStepRelArg + MI0Re); + *(pResMI + 1) = (float)((MI1Im - MI0Im)*InvStepRelArg + MI0Im); + return 0; + } + int MutualIntensityComponentSimpleInterpol2D(float** ExPtrs, float** ExPtrsT, float** EzPtrs, float** EzPtrsT, double Arg1, double Arg2, int PolCom, float* pResMI) + {//OC09092018 + float MI00[2], MI10[2], MI01[2], MI11[2]; + int res = 0; + if(res = MutualIntensityComponent(*ExPtrs, *ExPtrsT, *EzPtrs, *EzPtrsT, PolCom, MI00)) return res; + if(res = MutualIntensityComponent(*(ExPtrs + 1), *(ExPtrsT + 1), *(EzPtrs + 1), *(EzPtrsT + 1), PolCom, MI10)) return res; + if(res = MutualIntensityComponent(*(ExPtrs + 2), *(ExPtrsT + 2), *(EzPtrs + 2), *(EzPtrsT + 2), PolCom, MI01)) return res; + if(res = MutualIntensityComponent(*(ExPtrs + 3), *(ExPtrsT + 3), *(EzPtrs + 3), *(EzPtrsT + 3), PolCom, MI11)) return res; + double Arg1Arg2 = Arg1*Arg2; + double MI00Re = *MI00, MI00Im = *(MI00 + 1); + double MI10Re = *MI10, MI10Im = *(MI10 + 1); + double MI01Re = *MI01, MI01Im = *(MI01 + 1); + double MI11Re = *MI11, MI11Im = *(MI11 + 1); + *pResMI = (float)((MI00Re - MI01Re - MI10Re + MI11Re)*Arg1Arg2 + (MI10Re - MI00Re)*Arg1 + (MI01Re - MI00Re)*Arg2 + MI00Re); + *(pResMI + 1) = (float)((MI00Im - MI01Im - MI10Im + MI11Im)*Arg1Arg2 + (MI10Im - MI00Im)*Arg1 + (MI01Im - MI00Im)*Arg2 + MI00Im); + return 0; + } + int MutualIntensityComponent(float* pEx, float* pExT, float* pEz, float* pEzT, int PolCom, float* pResMI) + {//OC09092018 + //NOTE: This is based on M.I. definition as: E(x)E*(x'), which differs from existing definition in literature: E*(x)E(x') + //The two definitions are related by complex conjugation: E*(x)E(x') = (E(x)E*(x'))* + double ExRe = 0., ExIm = 0., EzRe = 0., EzIm = 0.; + double ExReT = 0., ExImT = 0., EzReT = 0., EzImT = 0.; + if(EhOK) { ExRe = *pEx; ExIm = *(pEx + 1); ExReT = *pExT; ExImT = *(pExT + 1);} + if(EvOK) { EzRe = *pEz; EzIm = *(pEz + 1); EzReT = *pEzT; EzImT = *(pEzT + 1);} + + switch(PolCom) + { + case 0: // Lin. Hor. + { + *pResMI = (float)(ExRe*ExReT + ExIm*ExImT); + *(pResMI + 1) = (float)(ExIm*ExReT - ExRe*ExImT); + return 0; + } + case 1: // Lin. Vert. + { + *pResMI = (float)(EzRe*EzReT + EzIm*EzImT); + *(pResMI + 1) = (float)(EzIm*EzReT - EzRe*EzImT); + return 0; + } + case 2: // Linear 45 deg. + { + double ExRe_p_EzRe = ExRe + EzRe, ExIm_p_EzIm = ExIm + EzIm; + double ExRe_p_EzReT = ExReT + EzReT, ExIm_p_EzImT = ExImT + EzImT; + *pResMI = (float)(0.5*(ExRe_p_EzRe*ExRe_p_EzReT + ExIm_p_EzIm*ExIm_p_EzImT)); //? + *(pResMI + 1) = (float)(0.5*(ExIm_p_EzIm*ExRe_p_EzReT - ExRe_p_EzRe*ExIm_p_EzImT)); //? + return 0; + } + case 3: // Linear 135 deg. + { + double ExRe_mi_EzRe = ExRe - EzRe, ExIm_mi_EzIm = ExIm - EzIm; + double ExRe_mi_EzReT = ExReT - EzReT, ExIm_mi_EzImT = ExImT - EzImT; + *pResMI = (float)(0.5*(ExRe_mi_EzRe*ExRe_mi_EzReT + ExIm_mi_EzIm*ExIm_mi_EzImT)); //? + *(pResMI + 1) = (float)(0.5*(ExIm_mi_EzIm*ExRe_mi_EzReT - ExRe_mi_EzRe*ExIm_mi_EzImT)); //? + return 0; + } + case 4: // Circ. Right + { + double ExRe_mi_EzIm = ExRe - EzIm, ExIm_p_EzRe = ExIm + EzRe; + double ExRe_mi_EzImT = ExReT - EzImT, ExIm_p_EzReT = ExImT + EzReT; + *pResMI = (float)(0.5*(ExRe_mi_EzIm*ExRe_mi_EzImT + ExIm_p_EzRe*ExIm_p_EzReT)); //? + *(pResMI + 1) = (float)(0.5*(ExIm_p_EzRe*ExRe_mi_EzImT - ExRe_mi_EzIm*ExIm_p_EzReT)); //? + return 0; + } + case 5: // Circ. Left + { + double ExRe_p_EzIm = ExRe + EzIm, ExIm_mi_EzRe = ExIm - EzRe; + double ExRe_p_EzImT = ExReT + EzImT, ExIm_mi_EzReT = ExImT - EzReT; + *pResMI = (float)(0.5*(ExRe_p_EzIm*ExRe_p_EzImT + ExIm_mi_EzRe*ExIm_mi_EzReT)); //? + *(pResMI + 1) = (float)(0.5*(ExIm_mi_EzRe*ExRe_p_EzImT - ExRe_p_EzIm*ExIm_mi_EzReT)); //? + return 0; + } + case -1: // s0 + { + *pResMI = (float)(ExRe*ExReT + ExIm*ExImT + EzRe*EzReT + EzIm*EzImT); + *(pResMI + 1) = (float)(ExIm*ExReT - ExRe*ExImT + EzIm*EzReT - EzRe*EzImT); + return 0; + } + case -2: // s1 + { + *pResMI = (float)(ExRe*ExReT + ExIm*ExImT - (EzRe*EzReT + EzIm*EzImT)); + *(pResMI + 1) = (float)(ExIm*ExReT - ExRe*ExImT - (EzIm*EzReT - EzRe*EzImT)); + return 0; + } + case -3: // s2 + { + *pResMI = (float)(ExImT*EzIm + ExIm*EzImT + ExReT*EzRe + ExRe*EzReT); + *(pResMI + 1) = (float)(ExReT*EzIm - ExRe*EzImT - ExImT*EzRe + ExIm*EzReT); + return 0; + } + case -4: // s3 + { + *pResMI = (float)(ExReT*EzIm + ExRe*EzImT - ExImT*EzRe - ExIm*EzReT); + *(pResMI + 1) = (float)(ExIm*EzImT - ExImT*EzIm - ExReT*EzRe + ExRe*EzReT); + return 0; + } + default: // total mutual intensity, same as s0 + { + *pResMI = (float)(ExRe*ExReT + ExIm*ExImT + EzRe*EzReT + EzIm*EzImT); + *(pResMI + 1) = (float)(ExIm*ExReT - ExRe*ExImT + EzIm*EzReT - EzRe*EzImT); + return 0; + //return CAN_NOT_EXTRACT_MUT_INT; + } + } + return 0; + } + + static double IntCylCrd(double ph, void* par) + { + srTAuxInt2DIntegOverAzim *p = (srTAuxInt2DIntegOverAzim*)par; + double r = p->r; + if(p->pfI2D) return CGenMathInterp::InterpOnRegMesh2d((p->x0) + r*cos(ph), (p->y0) + r*sin(ph), p->xMin, p->xStep, p->nx, p->yMin, p->yStep, p->ny, p->pfI2D, p->ordInterp); + else return CGenMathInterp::InterpOnRegMesh2d((p->x0) + r*cos(ph), (p->y0) + r*sin(ph), p->xMin, p->xStep, p->nx, p->yMin, p->yStep, p->ny, p->pdI2D, p->ordInterp); + } + + static void IntProc(srTWaveAccessData* pwI1, srTWaveAccessData* pwI2, double* arPar); + static void Int2DIntegOverAzim(srTWaveAccessData* pwI1, srTWaveAccessData* pwI2, double* arPar); static void ComponInteg(srTDataMD* pIntensOrigData, srTDataMD* pIntegParData, srTDataMD* pIntegResData); static void ComponIntegVsPhotEn(srTDataMD* pIntensOrigData, double eMin, double eMax, srTDataMD* pIntegResData); diff --git a/cpp/src/core/srradstr.cpp b/cpp/src/core/srradstr.cpp index 5f8202d3..325443ba 100644 --- a/cpp/src/core/srradstr.cpp +++ b/cpp/src/core/srradstr.cpp @@ -31,6 +31,7 @@ extern int (*pgWfrExtModifFunc)(int Action, srTSRWRadInData* pWfrIn, char PolComp); extern int (*gpWfrModifFunc)(int action, SRWLWfr* pWfrIn, char pol); //SRWLIB +extern char* (*gpAllocArrayFunc)(char type, long long len); //OC15082018 //************************************************************************* @@ -756,8 +757,8 @@ void srTSRWRadStructAccessData::OutSRWRadPtrs(SRWLWfr& srwlWfr) //************************************************************************* //int srTSRWRadStructAccessData::ModifyWfrNeNxNz(char PolarizComp) -int srTSRWRadStructAccessData::ModifyWfrNeNxNz(char PolarizComp, bool backupIsReq) //OC131115 -{ +int srTSRWRadStructAccessData::ModifyWfrNeNxNz(char PolarizComp, bool backupIsReq) +{//OC131115 #if defined(_SRWDLL) || defined(SRWLIB_STATIC) || defined(SRWLIB_SHARED) int res = 0; if(BaseRadWasEmulated) return ReAllocBaseRadAccordingToNeNxNz(PolarizComp); @@ -795,6 +796,30 @@ int srTSRWRadStructAccessData::ModifyWfrNeNxNz(char PolarizComp, bool backupIsRe //************************************************************************* +int srTSRWRadStructAccessData::AllocExtIntArray(char type, char dep, char*& pcAlloc) +{//OC18082018 +#if defined(SRWLIB_STATIC) || defined(SRWLIB_SHARED) + + pcAlloc = 0; + if(gpAllocArrayFunc != 0) + { + char typeAr = 'f'; + if(type == 4) typeAr = 'd'; //single-e rad. phase + + long long np = GetIntNumPts(dep); + if(np > 0) + { + pcAlloc = (*gpAllocArrayFunc)(typeAr, np); + if(pcAlloc == 0) return SRWL_EXT_ARRAY_ALLOC_FAILED; + } + } + +#endif + return 0; +} + +//************************************************************************* + int srTSRWRadStructAccessData::DeleteWfrBackupData(char PolarizComp) {//OC131115 #if defined(SRWLIB_STATIC) || defined(SRWLIB_SHARED) @@ -4000,6 +4025,76 @@ bool srTSRWRadStructAccessData::CheckIfQuadTermTreatIsBenefit(char cutX_or_Z, ch return (numDerE_SignChangeAfter <= numDerE_SignChange); } +//************************************************************************* + +void srTSRWRadStructAccessData::GetIntMesh(char dep, SRWLRadMesh& mesh) //OC23082018 +{//This assumes center values for the intensity distribution are defined in mesh.eStart, mesh.xStart, mesh.yStart at input + mesh.ne = mesh.nx = mesh.ny = 1; + if(dep == 0) + { + mesh.ne = ne; + mesh.eStart = eStart; + mesh.eFin = eStart + eStep*(ne - 1); + //Keep mesh.xStart, mesh.yStart as they define "central" values of the intensity distribution + } + else if(dep == 1) + { + mesh.nx = nx; + mesh.xStart = xStart; + mesh.xFin = xStart + xStep*(nx - 1); + //Keep mesh.eStart, mesh.yStart as they define "central" values of the intensity distribution + } + else if(dep == 2) + { + mesh.ny = nz; + mesh.yStart = zStart; + mesh.yFin = zStart + zStep*(nz - 1); + //Keep mesh.eStart, mesh.xStart as they define "central" values of the intensity distribution + } + else if(dep == 3) + { + mesh.nx = nx; + mesh.xStart = xStart; + mesh.xFin = xStart + xStep*(nx - 1); + mesh.ny = nz; + mesh.yStart = zStart; + mesh.yFin = zStart + zStep*(nz - 1); + //Keep mesh.eStart as it defines "central" value of the intensity distribution + } + else if(dep == 4) + { + mesh.ne = ne; + mesh.eStart = eStart; + mesh.eFin = eStart + eStep*(ne - 1); + mesh.nx = nx; + mesh.xStart = xStart; + mesh.xFin = xStart + xStep*(nx - 1); + //Keep mesh.yStart as it defines "central" value of the intensity distribution + } + else if(dep == 5) + { + mesh.ne = ne; + mesh.eStart = eStart; + mesh.eFin = eStart + eStep*(ne - 1); + mesh.ny = nz; + mesh.yStart = zStart; + mesh.yFin = zStart + zStep*(nz - 1); + //Keep mesh.xStart as it defines "central" value of the intensity distribution + } + else if(dep == 6) + { + mesh.ne = ne; + mesh.eStart = eStart; + mesh.eFin = eStart + eStep*(ne - 1); + mesh.nx = nx; + mesh.xStart = xStart; + mesh.xFin = xStart + xStep*(nx - 1); + mesh.ny = nz; + mesh.yStart = zStart; + mesh.yFin = zStart + zStep*(nz - 1); + } +} + //************************************************************************* /** void srTSRWRadStructAccessData::EstimWfrRadCen(double& resR, double& resCen, char cutX_or_Z, char fldX_or_Z, double relArgRange, double relArgCenOther) diff --git a/cpp/src/core/srradstr.h b/cpp/src/core/srradstr.h index 65da8dbc..81f5f015 100644 --- a/cpp/src/core/srradstr.h +++ b/cpp/src/core/srradstr.h @@ -55,6 +55,8 @@ struct SRWLStructWaveFront; typedef struct SRWLStructWaveFront SRWLWfr; struct SRWLStructParticleBeam; typedef struct SRWLStructParticleBeam SRWLPartBeam; +struct SRWLStructRadMesh; +typedef struct SRWLStructRadMesh SRWLRadMesh; //************************************************************************* @@ -217,6 +219,7 @@ class srTSRWRadStructAccessData : public CGenObject { //int ModifyWfrNeNxNz(char PolarizComp = 0); int ModifyWfrNeNxNz(char PolarizComp = 0, bool backupIsReq = false); //OC131115 int DeleteWfrBackupData(char PolarizComp = 0); //OC151115 + int AllocExtIntArray(char type, char dep, char*& pcAlloc); //OC18082018 int GetWfrStructNames(srTSRWRadStructWaveNames& RadStructNames); int CreateNewWfrStruct(srTSRWRadStructWaveNames& Names); @@ -248,6 +251,7 @@ class srTSRWRadStructAccessData : public CGenObject { //void EstimWfrRadCen(double& resR, double& resCen, char cutX_or_Z, char fldX_or_Z=0, double relArgRange=0.2, double relArgCenOther=0.5); bool CheckIfQuadTermTreatIsBenefit(char cutX_or_Z, char fldX_or_Z=0); + void GetIntMesh(char dep, SRWLRadMesh& mesh); //OC23082018 void SetupSrwWfrAuxData() { @@ -979,6 +983,19 @@ class srTSRWRadStructAccessData : public CGenObject { else return true; } + long long GetIntNumPts(char dep) //OC18082018 + {//To add dependence on type of intensity when/if it is extended to mutual intensity and related charact. + long long resNp = 0; + if(dep == 0) resNp = ne; + else if(dep == 1) resNp = nx; + else if(dep == 2) resNp = nz; + else if(dep == 3) resNp = ((long long)nx)*((long long)nz); + else if(dep == 4) resNp = ((long long)ne)*((long long)nx); + else if(dep == 5) resNp = ((long long)ne)*((long long)nz); + else if(dep == 6) resNp = ((long long)ne)*((long long)nx)*((long long)nz); + return resNp; + } + void DeleteElecFieldArrays() { if(pBaseRadX != 0) delete[] pBaseRadX; pBaseRadX = 0; diff --git a/cpp/src/core/srstraux.h b/cpp/src/core/srstraux.h index c5206f78..5fdc1adf 100644 --- a/cpp/src/core/srstraux.h +++ b/cpp/src/core/srstraux.h @@ -22,6 +22,7 @@ #include "srinterf.h" #include "cmplxd.h" #include "srercode.h" +#include "srwlib.h" #include @@ -1307,6 +1308,96 @@ struct srTWaveAccessData { srTWaveAccessData() { + Init(); //OC13112018 + + //pWaveData = 0; + //*WaveType = '\0'; + //AmOfDims = -1; + //for(int i=0; i<10; i++) + //{ + // DimSizes[i] = -1; + // DimStartValues[i] = 1.E+23; + // DimSteps[i] = 1.E+23; + // *(DimUnits[i]) = '\0'; + //} + //*NameOfWave = '\0'; + //*DataUnits = '\0'; + } + + srTWaveAccessData(char* pcData, char typeData, SRWLRadMesh* pMesh) + {//OC13112018 + Init(); + + pWaveData = pcData; + WaveType[0] = typeData; WaveType[1] = '\0'; + + int nDims = 0; + int n1 = 0, n2 = 0, n3 = 0; + double start1 = 0, start2 = 0, start3 = 0; + double step1 = 0, step2 = 0, step3 = 0; + if(pMesh->ne > 1) + { + nDims++; + n1 = pMesh->ne; + start1 = pMesh->eStart; + step1 = (pMesh->eFin - start1)/(n1 - 1); + } + if(pMesh->nx > 1) + { + nDims++; + if(n1 == 0) + { + n1 = pMesh->nx; + start1 = pMesh->xStart; + step1 = (pMesh->xFin - start1)/(n1 - 1); + } + else + { + n2 = pMesh->nx; + start2 = pMesh->xStart; + step2 = (pMesh->xFin - start2)/(n2 - 1); + } + } + if(pMesh->ny > 1) + { + nDims++; + if(n1 == 0) + { + n1 = pMesh->ny; + start1 = pMesh->yStart; + step1 = (pMesh->yFin - start1)/(n1 - 1); + } + else if(n2 == 0) + { + n2 = pMesh->ny; + start2 = pMesh->yStart; + step2 = (pMesh->yFin - start2)/(n2 - 1); + } + else + { + n3 = pMesh->ny; + start3 = pMesh->yStart; + step3 = (pMesh->yFin - start3)/(n3 - 1); + } + } + + AmOfDims = nDims; + + DimSizes[0] = n1; + DimSizes[1] = n2; + DimSizes[2] = n3; + DimStartValues[0] = start1; + DimStartValues[1] = start2; + DimStartValues[2] = start3; + DimSteps[0] = step1; + DimSteps[1] = step2; + DimSteps[2] = step3; + + //To process Mutual Intensity case: pMesh->type == 'm' ! + } + + void Init() + {//OC13112018 pWaveData = 0; *WaveType = '\0'; AmOfDims = -1; diff --git a/cpp/src/ext/genmath/gmfft.cpp b/cpp/src/ext/genmath/gmfft.cpp index d3a460c7..7d0e4392 100644 --- a/cpp/src/ext/genmath/gmfft.cpp +++ b/cpp/src/ext/genmath/gmfft.cpp @@ -14,6 +14,13 @@ #include "gmfft.h" +//#include "srwlib.h" //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP + +#ifdef _WITH_OMP //OC27102018 +//SY: adopted for OpenMP +#include "omp.h" +#endif + //************************************************************************* long CGenMathFFT::GoodNumbers[] = { @@ -214,7 +221,10 @@ int CGenMathFFT2D::AuxDebug_TestFFT_Plans() //************************************************************************* //Forward FFT (FFT2DInfo.Dir = 1?): Int f(x,y)*exp(-i*2*Pi*(qx*x + qy*y)) dx dy //Backward FFT (FFT2DInfo.Dir = -1?): Int f(qx,qy)*exp(i*2*Pi*(qx*x + qy*y)) dqx dqy -int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) +//int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) +//Modification by S.Yakubov for parallelizing SRW via OpenMP: +// SY: creation (and deletion) of FFTW plans is not thread-safe. Therefore added option to use precreated plans +int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo, fftwnd_plan* pPrecreatedPlan2DFFT) //OC27102018 {// Assumes Nx, Ny even ! const double RelShiftTol = 1.E-06; @@ -270,7 +280,12 @@ int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) if(FFT2DInfo.Dir > 0) { - Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_FORWARD, FFTW_IN_PLACE); + //Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_FORWARD, FFTW_IN_PLACE); + //OC27102018 + //SY: adopted for OpenMP + if(pPrecreatedPlan2DFFT == 0) Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_FORWARD, FFTW_IN_PLACE); + else Plan2DFFT = *pPrecreatedPlan2DFFT; + if(Plan2DFFT == 0) return ERROR_IN_FFT; fftwnd(Plan2DFFT, 1, DataToFFT, 1, 0, DataToFFT, 1, 0); RepairSignAfter2DFFT(DataToFFT); @@ -278,7 +293,12 @@ int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) } else { - Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_BACKWARD, FFTW_IN_PLACE); + //Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_BACKWARD, FFTW_IN_PLACE); + //OC27102018 + //SY: adopted for OpenMP + if(pPrecreatedPlan2DFFT == 0) Plan2DFFT = fftw2d_create_plan(Ny, Nx, FFTW_BACKWARD, FFTW_IN_PLACE); + else Plan2DFFT = *pPrecreatedPlan2DFFT; + if(Plan2DFFT == 0) return ERROR_IN_FFT; RotateDataAfter2DFFT(DataToFFT); RepairSignAfter2DFFT(DataToFFT); @@ -295,7 +315,10 @@ int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) if(NeedsShiftAfterX || NeedsShiftAfterY) TreatShifts(DataToFFT); //OC_NERSC: to comment-out the following line for NERSC (to avoid crash with "python-mpi") - fftwnd_destroy_plan(Plan2DFFT); + //fftwnd_destroy_plan(Plan2DFFT); + //OC27102018 + //SY: adopted for OpenMP + if(pPrecreatedPlan2DFFT == 0) fftwnd_destroy_plan(Plan2DFFT); if(ArrayShiftX != 0) { @@ -313,6 +336,10 @@ int CGenMathFFT2D::Make2DFFT(CGenMathFFT2DInfo& FFT2DInfo) //Backward FFT: Int f(qx)*exp(i*2*Pi*qx*x)dqx int CGenMathFFT1D::Make1DFFT(CGenMathFFT1DInfo& FFT1DInfo) {// Assumes Nx, Ny even ! + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + const double RelShiftTol = 1.E-06; SetupLimitsTr(FFT1DInfo); @@ -365,6 +392,9 @@ int CGenMathFFT1D::Make1DFFT(CGenMathFFT1DInfo& FFT1DInfo) TreatShift(DataToFFT, FFT1DInfo.HowMany); } + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::Make1DFFT : before fft",&start); + if(FFT1DInfo.Dir > 0) { int flags = FFTW_ESTIMATE; @@ -374,13 +404,31 @@ int CGenMathFFT1D::Make1DFFT(CGenMathFFT1DInfo& FFT1DInfo) pOutDataFFT = 0; //OC03092016 (see FFTW 2.1.5 doc clause above) } Plan1DFFT = fftw_create_plan(Nx, FFTW_FORWARD, flags); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::Make1DFFT : fft create plan dir>0",&start); + if(Plan1DFFT == 0) return ERROR_IN_FFT; +#ifndef _WITH_OMP //OC27102018 //fftw(Plan1DFFT, FFT1DInfo.HowMany, DataToFFT, 1, Nx, OutDataFFT, 1, Nx); fftw(Plan1DFFT, FFT1DInfo.HowMany, DataToFFT, 1, Nx, pOutDataFFT, 1, Nx); //OC03092016 - +#else //OC27102018 + //SY: split one call into many (for OpenMP) + #pragma omp parallel for if (omp_get_num_threads()==1) // to avoid nested multi-threading (just in case) + for(int i=0; i0",&start); RepairSignAfter1DFFT(OutDataFFT, FFT1DInfo.HowMany); + //srwlPrintTime("::Make1DFFT : repair dir>0",&start); RotateDataAfter1DFFT(OutDataFFT, FFT1DInfo.HowMany); + //srwlPrintTime("::Make1DFFT : rotate dir>0",&start); } else { @@ -391,37 +439,69 @@ int CGenMathFFT1D::Make1DFFT(CGenMathFFT1DInfo& FFT1DInfo) pOutDataFFT = 0; //OC03092016 (see FFTW 2.1.5 doc clause above) } Plan1DFFT = fftw_create_plan(Nx, FFTW_BACKWARD, flags); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("::Make1DFFT : fft create plan dir<0",&start); + if(Plan1DFFT == 0) return ERROR_IN_FFT; RotateDataAfter1DFFT(DataToFFT, FFT1DInfo.HowMany); + //srwlPrintTime("::Make1DFFT : rotate dir<0",&start); + RepairSignAfter1DFFT(DataToFFT, FFT1DInfo.HowMany); + //srwlPrintTime("::Make1DFFT : repair dir<0",&start); +#ifndef _WITH_OMP //OC27102018 //fftw(Plan1DFFT, FFT1DInfo.HowMany, DataToFFT, 1, Nx, OutDataFFT, 1, Nx); fftw(Plan1DFFT, FFT1DInfo.HowMany, DataToFFT, 1, Nx, pOutDataFFT, 1, Nx); //OC03092016 +#else //OC27102018 + //SY: split one call into many (for OpenMP) + #pragma omp parallel for if (omp_get_num_threads()==1) // to avoid nested multi-threading (just in case) + for(int i=0; ire = -tMany->re; tMany->im = -tMany->im; + // tMany += Nx; + // } + // } + // t++; s = -s; + //} + //OC27102018 + //SY: optimized, adopt for OpenMP +#ifdef _WITH_OMP + #pragma omp parallel for +#endif + for(long ix=1; ixre = -tMany->re; tMany->im = -tMany->im; - tMany += Nx; - } + tMany->re = -tMany->re; tMany->im = -tMany->im; + tMany += Nx; } - t++; s = -s; } } void RotateDataAfter1DFFT(FFTW_COMPLEX* pAfterFFT, long HowMany) {// Assumes Nx even ! +#ifndef _WITH_OMP //OC27102018 FFTW_COMPLEX *t1 = pAfterFFT, *t2 = pAfterFFT + HalfNx; FFTW_COMPLEX Buf; for(long ix=0; ixre *= (FFTW_REAL)Mult; tMany->im *= (FFTW_REAL)Mult; + tMany += Nx; + } + } +#endif } int SetupAuxDataForSharpEdgeCorr(CGenMathFFT1DInfo&, CGenMathAuxDataForSharpEdgeCorr1D&); diff --git a/cpp/src/ext/genmath/gmfunc.h b/cpp/src/ext/genmath/gmfunc.h index b12882ba..e065369a 100644 --- a/cpp/src/ext/genmath/gmfunc.h +++ b/cpp/src/ext/genmath/gmfunc.h @@ -74,7 +74,8 @@ class CGenMathFunc /** Computes x^2*Kn(x)^2 */ - static double AuxFuncK2d3e2_xe2(double x) + static double AuxFuncK2d3e2_xe2(double x, void* pv=0) //OC20112018 + //static double AuxFuncK2d3e2_xe2(double x) { double KmuVal = 0; Kmu(0, 2./3., x, KmuVal); @@ -83,7 +84,8 @@ class CGenMathFunc /** Computes x^2*Kn(x)^2 */ - static double AuxFuncIntK5d3_x(double x) + static double AuxFuncIntK5d3_x(double x, void* pv=0) //OC20112018 + //static double AuxFuncIntK5d3_x(double x) { double KmuVal = 0; Kmu(1, 5./3., x, KmuVal); diff --git a/cpp/src/ext/genmath/gminterp.h b/cpp/src/ext/genmath/gminterp.h index 4ae64ba7..83519958 100644 --- a/cpp/src/ext/genmath/gminterp.h +++ b/cpp/src/ext/genmath/gminterp.h @@ -621,6 +621,140 @@ class CGenMathInterp {// assumes 0 <= xr <= 1; 0 <= yr <= 1; f00 := f|xr=0,yr=0; f10 := f|xr=1,yr=0; return (f11 + f00 - f10 - f01)*xr*yr + (f10 - f00)*xr + (f01 - f00)*xr + f00; } + + template static double InterpOnRegMesh2d(double x, double y, double x_min, double x_step, long nx, double y_min, double y_step, long ny, T* ar_f, char ord=3, long ix_per=1, long ix_ofst=0) + {//OC20112018: "copied" from uti_math.py: uti_math.interp_2d + + if((x_step == 0) || (y_step == 0) || (ar_f == 0) || (ord < 1) || (ord > 3)) throw CAN_NOT_FIND_IND_FOR_INTERP; + const double truncTol = 1.e-12; //to steer + + if(ord == 1) //bi-linear interpolation based on 4 points + { + long ix0 = (long)((x - x_min)/x_step + truncTol); + if(ix0 < 0) ix0 = 0; + else if(ix0 >= nx - 1) ix0 = nx - 2; + + long ix1 = ix0 + 1; + double tx = (x - (x_min + x_step*ix0))/x_step; + + long iy0 = (long)((y - y_min)/y_step + truncTol); + if(iy0 < 0) iy0 = 0; + else if(iy0 >= ny - 1) iy0 = ny - 2; + + long iy1 = iy0 + 1; + double ty = (y - (y_min + y_step*iy0))/y_step; + + long long nx_ix_per = nx*ix_per; + long long iy0_nx_ix_per = iy0*nx_ix_per; + long long iy1_nx_ix_per = iy1*nx_ix_per; + long long ix0_ix_per_p_ix_ofst = ix0*ix_per + ix_ofst; + long long ix1_ix_per_p_ix_ofst = ix1*ix_per + ix_ofst; + + double a00 = *(ar_f + (iy0_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f10 = *(ar_f + (iy0_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double f01 = *(ar_f + (iy1_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f11 = *(ar_f + (iy1_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double a10 = f10 - a00; + double a01 = f01 - a00; + double a11 = a00 - f01 - f10 + f11; + return a00 + tx*(a10 + ty*a11) + ty*a01; + } + else if(ord == 2) //bi-quadratic interpolation based on 6 points + { + long ix0 = (long)((x - x_min)/x_step + truncTol); + if(ix0 < 1) ix0 = 1; + else if(ix0 >= nx - 1) ix0 = nx - 2; + + long ixm1 = ix0 - 1; + long ix1 = ix0 + 1; + double tx = (x - (x_min + x_step*ix0))/x_step; + + long iy0 = (long)((y - y_min)/y_step + truncTol); + if(iy0 < 1) iy0 = 1; + else if(iy0 >= ny - 1) iy0 = ny - 2; + + long iym1 = iy0 - 1; + long iy1 = iy0 + 1; + double ty = (y - (y_min + y_step*iy0))/y_step; + + long long nx_ix_per = nx*ix_per; + long long iym1_nx_ix_per = iym1*nx_ix_per; + long long iy0_nx_ix_per = iy0*nx_ix_per; + long long iy1_nx_ix_per = iy1*nx_ix_per; + long long ixm1_ix_per_p_ix_ofst = ixm1*ix_per + ix_ofst; + long long ix0_ix_per_p_ix_ofst = ix0*ix_per + ix_ofst; + long long ix1_ix_per_p_ix_ofst = ix1*ix_per + ix_ofst; + + double fm10 = *(ar_f + (iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst)); + double a00 = *(ar_f + (iy0_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f10 = *(ar_f + (iy0_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double f0m1 = *(ar_f + (iym1_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f01 = *(ar_f + (iy1_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f11 = *(ar_f + (iy1_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double a10 = 0.5*(f10 - fm10); + double a01 = 0.5*(f01 - f0m1); + double a11 = a00 - f01 - f10 + f11; + double a20 = 0.5*(f10 + fm10) - a00; + double a02 = 0.5*(f01 + f0m1) - a00; + return a00 + tx*(a10 + tx*a20 + ty*a11) + ty*(a01 + ty*a02); + } + else if(ord == 3) //bi-cubic interpolation based on 12 points + { + long ix0 = (long)((x - x_min)/x_step + truncTol); + if(ix0 < 1) ix0 = 1; + else if(ix0 >= nx - 2) ix0 = nx - 3; + + long ixm1 = ix0 - 1; + long ix1 = ix0 + 1; + long ix2 = ix0 + 2; + double tx = (x - (x_min + x_step*ix0))/x_step; + + long iy0 = (long)((y - y_min)/y_step + truncTol); + if(iy0 < 1) iy0 = 1; + else if(iy0 >= ny - 2) iy0 = ny - 3; + + long iym1 = iy0 - 1; + long iy1 = iy0 + 1; + long iy2 = iy0 + 2; + double ty = (y - (y_min + y_step*iy0))/y_step; + + long long nx_ix_per = nx*ix_per; + long long iym1_nx_ix_per = iym1*nx_ix_per; + long long iy0_nx_ix_per = iy0*nx_ix_per; + long long iy1_nx_ix_per = iy1*nx_ix_per; + long long iy2_nx_ix_per = iy2*nx_ix_per; + long long ixm1_ix_per_p_ix_ofst = ixm1*ix_per + ix_ofst; + long long ix0_ix_per_p_ix_ofst = ix0*ix_per + ix_ofst; + long long ix1_ix_per_p_ix_ofst = ix1*ix_per + ix_ofst; + long long ix2_ix_per_p_ix_ofst = ix2*ix_per + ix_ofst; + + double f0m1 = *(ar_f + (iym1_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f1m1 = *(ar_f + (iym1_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double fm10 = *(ar_f + (iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst)); + double a00 = *(ar_f + (iy0_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f10 = *(ar_f + (iy0_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double f20 = *(ar_f + (iy0_nx_ix_per + ix2_ix_per_p_ix_ofst)); + double fm11 = *(ar_f + (iy1_nx_ix_per + ixm1_ix_per_p_ix_ofst)); + double f01 = *(ar_f + (iy1_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f11 = *(ar_f + (iy1_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double f21 = *(ar_f + (iy1_nx_ix_per + ix2_ix_per_p_ix_ofst)); + double f02 = *(ar_f + (iy2_nx_ix_per + ix0_ix_per_p_ix_ofst)); + double f12 = *(ar_f + (iy2_nx_ix_per + ix1_ix_per_p_ix_ofst)); + double a10 = -0.5*a00 + f10 - f20/6. - fm10/3.; + double a01 = -0.5*a00 + f01 - f02/6. - f0m1/3.; + double a11 = -0.5*(f01 + f10) + (f02 - f12 + f20 - f21)/6. + (f0m1 - f1m1 + fm10 - fm11)/3. + f11; + double a20 = -a00 + 0.5*(f10 + fm10); + double a02 = -a00 + 0.5*(f01 + f0m1); + double a21 = a00 - f01 + 0.5*(f11 - f10 - fm10 + fm11); + double a12 = a00 - f10 + 0.5*(f11 - f01 - f0m1 + f1m1); + double a30 = 0.5*(a00 - f10) + (f20 - fm10)/6.; + double a03 = 0.5*(a00 - f01) + (f02 - f0m1)/6.; + double a31 = 0.5*(f01 + f10 - f11 - a00) + (f21 + fm10 - f20 - fm11)/6.; + double a13 = 0.5*(f10 - f11 - a00 + f01) + (f0m1 + f12 - f02 - f1m1)/6.; + return a00 + tx*(a10 + tx*(a20 + tx*(a30 + ty*a31) + ty*a21) + ty*a11) + ty*(a01 + ty*(a02 + ty*(a03 + tx*a13) + tx*a12)); + } + else return 0; + } }; //------------------------------------------------------------------------- diff --git a/cpp/src/ext/genmath/gmmeth.cpp b/cpp/src/ext/genmath/gmmeth.cpp index 1a3826a6..cb9d7a91 100644 --- a/cpp/src/ext/genmath/gmmeth.cpp +++ b/cpp/src/ext/genmath/gmmeth.cpp @@ -33,9 +33,11 @@ bool CGenMathMeth::VectCheckIfCollinear(double xV1, double yV1, double zV1, doub //------------------------------------------------------------------------- -double CGenMathMeth::Integ1D_FuncWithEdgeDer(double (*pF)(double), double x1, double x2, double dFdx1, double dFdx2, double RelPrec) +double CGenMathMeth::Integ1D_FuncWithEdgeDer(double (*pF)(double, void*), double x1, double x2, double dFdx1, double dFdx2, double RelPrec, void* pv) //OC20112018 +//double CGenMathMeth::Integ1D_FuncWithEdgeDer(double (*pF)(double), double x1, double x2, double dFdx1, double dFdx2, double RelPrec) { - if((pF == 0) || (RelPrec <= 0)) return 0; + //if((pF == 0) || (RelPrec <= 0)) return 0; + if((pF == 0) || (RelPrec <= 0) || (x1 == x2)) return 0; const double wfe = 7./15.; const double wf1 = 16./15.; @@ -50,17 +52,22 @@ double CGenMathMeth::Integ1D_FuncWithEdgeDer(double (*pF)(double), double x1, do double wF; int LevelNo=0; - wF = (*pF)(x1); + wF = (*pF)(x1, pv); //OC20112018 + //wF = (*pF)(x1); double x = x1 + xStep; //int AmOfPass = (NpOnLevel - 3) >> 1; long long AmOfPass = (NpOnLevel - 3) >> 1; for(int i=0; i> 1; + long long AmOfPass = (NpOnLevel - 3) >> 1; + for(int i=0; i RelPrec*(::fabs(LocInt))); + + if(!NotFinishedYetFirstTest) + { + if(ExtraPassForAnyCase || SharplyGoesDown) NotFinishedYet = 0; + else ExtraPassForAnyCase = 1; + } + + Int = LocInt; + xStep = HalfStep; NpOnLevel *= 2; + } + return Int; +} + //------------------------------------------------------------------------- // //double CGenMathMeth::Integ1D_FuncDefByArray(double* FuncArr, long Np, double Step) diff --git a/cpp/src/ext/genmath/gmmeth.h b/cpp/src/ext/genmath/gmmeth.h index 9b120727..7c3f6c33 100644 --- a/cpp/src/ext/genmath/gmmeth.h +++ b/cpp/src/ext/genmath/gmmeth.h @@ -156,7 +156,9 @@ class CGenMathMeth static bool VectCheckIfCollinear(double xV1, double yV1, double zV1, double xV2, double yV2, double zV2, double RelPrec); - static double Integ1D_FuncWithEdgeDer(double (*pF)(double), double x1, double x2, double dFdx1, double dFdx2, double RelPrec); + //static double Integ1D_FuncWithEdgeDer(double (*pF)(double), double x1, double x2, double dFdx1, double dFdx2, double RelPrec); + static double Integ1D_FuncWithEdgeDer(double (*pF)(double, void*), double x1, double x2, double dFdx1, double dFdx2, double RelPrec, void* pv=0); //OC20112018 + static double Integ1D_Func(double (*pF)(double, void*), double x1, double x2, double RelPrec, void* pv=0); //OC02122018 //static double Integ1D_FuncDefByArray(double* FuncArr, long Np, double Step); //static double Integ1D_FuncDefByArray(float* FuncArr, long Np, double Step); @@ -164,7 +166,8 @@ class CGenMathMeth template static double Integ1D_FuncDefByArray(T* FuncArr, long long Np, double Step) { if((FuncArr == 0) || (Np < 2) || (Step == 0)) return 0; - if(Np == 2) return (double)(0.5*(FuncArr[0] + FuncArr[1])); + //if(Np == 2) return (double)(0.5*(FuncArr[0] + FuncArr[1])); + if(Np == 2) return (double)(0.5*Step*(FuncArr[0] + FuncArr[1])); //02122018 T *tFuncArr = FuncArr + 1; bool NpIsEven = (Np == ((Np >> 1) << 1)); diff --git a/cpp/src/lib/srerror.cpp b/cpp/src/lib/srerror.cpp index 7c0f0c96..b2d87b6e 100644 --- a/cpp/src/lib/srerror.cpp +++ b/cpp/src/lib/srerror.cpp @@ -243,6 +243,10 @@ CErrWarn::CErrWarn() error.push_back("Incorrect or insufficient parameters for spherical wave electric field calculation.\0"); //#186 error.push_back("Failed to determine array element index for interpolation.\0"); //#187 + error.push_back("Failed to allocate array in front-end / client environment.\0"); //#188 + error.push_back("Mutual intensity can not be extracted for these input parameters.\0"); //#189 + error.push_back("Incorrect input parameters for calculation of statistical characteristics of intensity.\0"); //#190 + error.push_back("Incorrect input parameters for processing intensity distributions.\0"); //#191 //}; diff --git a/cpp/src/lib/srwlib.cpp b/cpp/src/lib/srwlib.cpp index d4fdae97..4a92e42e 100644 --- a/cpp/src/lib/srwlib.cpp +++ b/cpp/src/lib/srwlib.cpp @@ -26,6 +26,9 @@ #include "srpersto.h" #include "srpowden.h" #include "srisosrc.h" +#include "srmatsta.h" + +//#include //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP //------------------------------------------------------------------------- // Global Variables (used in SRW/SRWLIB, some may be obsolete) @@ -47,6 +50,7 @@ int (*pgOptElemGetInfByNameFunc)(const char* sNameOptElem, char** pDescrStr, int //------------------------------------------------------------------------- int (*gpWfrModifFunc)(int action, SRWLWfr* pWfrIn, char pol) = 0; +char* (*gpAllocArrayFunc)(char type, long long len) = 0; //OC15082018 int (*gpCompProgressIndicFunc)(double curVal) = 0; //------------------------------------------------------------------------- @@ -96,6 +100,13 @@ EXP void CALL srwlUtiSetWfrModifFunc(int (*pExtFunc)(int action, SRWLWfr* pWfrIn //------------------------------------------------------------------------- +EXP void CALL srwlUtiSetAllocArrayFunc(char* (*pExtFunc)(char type, long long len)) //OC15082018 +{ + gpAllocArrayFunc = pExtFunc; +} + +//------------------------------------------------------------------------- + EXP void CALL srwlUtiSetProgrIndFunc(int (*pExtFunc)(double curVal)) { //if(pExtFunc != 0) gpCompProgressIndicFunc = pExtFunc; @@ -690,6 +701,9 @@ EXP int CALL srwlCalcPowDenSR(SRWLStokes* pStokes, SRWLPartBeam* pElBeam, SRWLPr EXP int CALL srwlCalcIntFromElecField(char* pInt, SRWLWfr* pWfr, char polar, char intType, char depType, double e, double x, double y) { + //double start; //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP + //get_walltime (&start); + if((pWfr == 0) || (pInt == 0)) return SRWL_INCORRECT_PARAM_FOR_INT_EXTR; try @@ -698,15 +712,23 @@ EXP int CALL srwlCalcIntFromElecField(char* pInt, SRWLWfr* pWfr, char polar, cha CHGenObj hWfr(&wfr, true); srTRadGenManip radGenManip(hWfr); - //Re-defining intType - //from SRWL convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Flux; 3- Multi-Elec. Flux; 4- Single-Elec. Rad. Phase; 5- Re(E); 6- Im(E); 7- Time or Photon Energy Integrated Intensity - //to old SRW convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Rad. Phase; 3- Re(E); 4- Single-Elec. Flux; 5- Multi-Elec. Flux; 6- Im(E); 7- Time or Photon Energy Integrated Intensity - if(intType == 2) intType = 4; - else if(intType == 3) intType = 5; - else if(intType == 4) intType = 2; - else if(intType == 5) intType = 3; - - radGenManip.ExtractRadiation((int)polar, (int)intType, (int)depType, wfr.Pres, e, x, y, pInt); + ////Re-defining intType + ////from SRWL convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Flux; 3- Multi-Elec. Flux; 4- Single-Elec. Rad. Phase; 5- Re(E); 6- Im(E); 7- Time or Photon Energy Integrated Intensity + ////to old SRW convention: 0- Single-Elec. Intensity; 1- Multi-Elec. Intensity; 2- Single-Elec. Rad. Phase; 3- Re(E); 4- Single-Elec. Flux; 5- Multi-Elec. Flux; 6- Im(E); 7- Time or Photon Energy Integrated Intensity + //if(intType == 2) intType = 4; + //else if(intType == 3) intType = 5; + //else if(intType == 4) intType = 2; + //else if(intType == 5) intType = 3; + //radGenManip.ExtractRadiation((int)polar, (int)intType, (int)depType, wfr.Pres, e, x, y, pInt); + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlCalcIntFromElecField : before ExtractRadiation",&start); + + radGenManip.ExtractRadiationSRWL(polar, intType, depType, wfr.Pres, e, x, y, pInt); //OC19082018 + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlCalcIntFromElecField : ExtractRadiation",&start); + //wfr.OutSRWRadPtrs(*pWfr); //not necessary? UtiWarnCheck(); } @@ -775,6 +797,10 @@ EXP int CALL srwlResizeElecField(SRWLWfr* pWfr, char type, double* par) EXP int CALL srwlSetRepresElecField(SRWLWfr* pWfr, char repr) { + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + if(pWfr == 0) return SRWL_INCORRECT_PARAM_FOR_CHANGE_REP; char reprCoordOrAng=0, reprFreqOrTime=0; @@ -787,8 +813,16 @@ EXP int CALL srwlSetRepresElecField(SRWLWfr* pWfr, char repr) srTSRWRadStructAccessData wfr(pWfr); int locErNo = 0; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlSetRepresElecField : before fft",&start); + if(reprCoordOrAng) locErNo = wfr.SetRepresCA(reprCoordOrAng); //set Coordinate or Angular representation else if(reprFreqOrTime) locErNo = wfr.SetRepresFT(reprFreqOrTime); //set Frequency or Time representation + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime(":srwlSetRepresElecField : wfr.SetRepresFT",&start); + if(locErNo) return locErNo; wfr.OutSRWRadPtrs(*pWfr); @@ -804,20 +838,36 @@ EXP int CALL srwlSetRepresElecField(SRWLWfr* pWfr, char repr) //------------------------------------------------------------------------- -EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt) +EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt, int nInt, char** arID, SRWLRadMesh* arIM, char** arI) //OC15082018 +//EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt) { if((pWfr == 0) || (pOpt == 0)) return SRWL_INCORRECT_PARAM_FOR_WFR_PROP; int locErNo = 0; + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //double start; + //get_walltime (&start); + try { srTCompositeOptElem optCont(*pOpt); srTSRWRadStructAccessData wfr(pWfr); if(locErNo = optCont.CheckRadStructForPropagation(&wfr)) return locErNo; - if(locErNo = optCont.PropagateRadiationGuided(wfr)) return locErNo; + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("srwlPropagElecField: CheckRadStructForPropagation",&start); + + //if(locErNo = optCont.PropagateRadiationGuided(wfr)) return locErNo; + if(locErNo = optCont.PropagateRadiationGuided(wfr, nInt, arID, arIM, arI)) return locErNo; //OC15082018 + + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("srwlPropagElecField: PropagateRadiationGuided",&start); wfr.OutSRWRadPtrs(*pWfr); + //Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: + //srwlPrintTime("srwlPropagElecField: PropagateRadiationGuided",&start); + UtiWarnCheck(); } catch(int erNo) @@ -1074,6 +1124,131 @@ EXP int CALL srwlUtiConvWithGaussian(char* pcData, char typeData, double* arMesh //------------------------------------------------------------------------- +EXP int CALL srwlUtiIntInf(double* arInf, char* pcData, char typeData, SRWLRadMesh* pMesh) +{//OC24092018 + if((arInf == 0) || (pcData == 0) || ((typeData != 'f') && (typeData != 'd')) || (pMesh == 0)) return SRWL_INCORRECT_PARAM_FOR_INT_STAT; + try + { + srTWaveAccessData InData(pcData, typeData, pMesh); //OC13112018 + if(InData.AmOfDims > 2) throw SRWL_INCORRECT_PARAM_FOR_INT_STAT; //to update in the future + +/** + srTWaveAccessData InData; + InData.pWaveData = pcData; + InData.WaveType[0] = typeData; InData.WaveType[1] = '\0'; + + int nDims = 0; + int n1 = 0, n2 = 0, n3 = 0; + double start1 = 0, start2 = 0, start3 = 0; + double step1 = 0, step2 = 0, step3 = 0; + if(pMesh->ne > 1) + { + nDims++; + n1 = pMesh->ne; + start1 = pMesh->eStart; + step1 = (pMesh->eFin - start1)/(n1 - 1); + } + if(pMesh->nx > 1) + { + nDims++; + if(n1 == 0) + { + n1 = pMesh->nx; + start1 = pMesh->xStart; + step1 = (pMesh->xFin - start1)/(n1 - 1); + } + else + { + n2 = pMesh->nx; + start2 = pMesh->xStart; + step2 = (pMesh->xFin - start2)/(n2 - 1); + } + } + if(pMesh->ny > 1) + { + nDims++; + if(n1 == 0) + { + n1 = pMesh->ny; + start1 = pMesh->yStart; + step1 = (pMesh->yFin - start1)/(n1 - 1); + } + else if(n2 == 0) + { + n2 = pMesh->ny; + start2 = pMesh->yStart; + step2 = (pMesh->yFin - start2)/(n2 - 1); + } + else + { + n3 = pMesh->ny; + start3 = pMesh->yStart; + step3 = (pMesh->yFin - start3)/(n3 - 1); + } + } + if(nDims > 2) throw SRWL_INCORRECT_PARAM_FOR_INT_STAT; //to update in the future + InData.AmOfDims = nDims; + + InData.DimSizes[0] = n1; + InData.DimSizes[1] = n2; + InData.DimSizes[2] = n3; + InData.DimStartValues[0] = start1; + InData.DimStartValues[1] = start2; + InData.DimStartValues[2] = start3; + InData.DimSteps[0] = step1; + InData.DimSteps[1] = step2; + InData.DimSteps[2] = step3; +**/ + + float arInfAux[5]; + srTWaveAccessData OutData; + OutData.pWaveData = (char*)arInfAux; + OutData.WaveType[0] = 'f'; + OutData.AmOfDims = 1; + OutData.DimSizes[0] = 5; //to update to 3D data case in the future + OutData.DimSizes[1] = 0; + OutData.DimStartValues[0] = 0; + OutData.DimSteps[0] = 1; + + srTAuxMatStat AuxMatStat; + int res = 0; + if(res = AuxMatStat.FindSimplestStat(InData, OutData)) throw res; + + //re-arranging res. data for eventual 3D case + for(int i=0; i<3; i++) arInf[i] = arInfAux[i]; + arInf[3] = 0; + arInf[4] = arInfAux[3]; + arInf[5] = arInfAux[4]; + arInf[6] = 0; + } + catch(int erNo) + { + return erNo; + } + return 0; +} + +//------------------------------------------------------------------------- + +EXP int CALL srwlUtiIntProc(char* pcI1, char typeI1, SRWLRadMesh* pMesh1, char* pcI2, char typeI2, SRWLRadMesh* pMesh2, double* arPar) +{//OC13112018 + if((pcI1 == 0) || ((typeI1 != 'f') && (typeI1 != 'd')) || (pMesh1 == 0) || + (pcI2 == 0) || ((typeI2 != 'f') && (typeI2 != 'd')) || (pMesh2 == 0) || (arPar == 0)) return SRWL_INCORRECT_PARAM_FOR_INT_PROC; + + try + { + srTWaveAccessData wI1(pcI1, typeI1, pMesh1), wI2(pcI2, typeI2, pMesh2); + srTRadGenManip::IntProc(&wI1, &wI2, arPar); + } + catch(int erNo) + { + return erNo; + } + return 0; +} + +//------------------------------------------------------------------------- + EXP int CALL srwlUtiUndFromMagFldTab(SRWLMagFldC* pUndCnt, SRWLMagFldC* pMagCnt, double* arPrecPar) { if((pUndCnt == 0) || (pMagCnt == 0) || (arPrecPar == 0)) return SRWL_INCORRECT_PARAM_FOR_CONV_MAG_2_PER; @@ -1148,3 +1323,35 @@ EXP int CALL srwlPropagRadMultiE(SRWLStokes* pStokes, SRWLWfr* pWfr0, SRWLOptC* } //------------------------------------------------------------------------- +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +/* +void get_walltime_(double* wcTime) { + clock_t tp; + tp = clock(); + *wcTime = (double)(((float)tp)/CLOCKS_PER_SEC); + // cout << "=== clock = " << tp << " CLOCKS_PER_SEC = " << CLOCKS_PER_SEC << "\n"; + // cout << "=== *wcTime = " << *wcTime << "\n"; +} + +EXP void CALL get_walltime(double* wcTime) { + get_walltime_(wcTime); +} +*/ +//------------------------------------------------------------------------- +//Added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP: +/* +EXP void CALL srwlPrintTime(const char* str, double* start){ +#ifdef MANUAL_PROFILING + double end; + get_walltime (&end); + double dif= end-*start; + if (dif > 0.1) + { + printf ("Elapsed: %80s %5.2f s\n",str,dif); + fflush(stdout); + } + *start=end; +#endif +} +*/ +//------------------------------------------------------------------------- diff --git a/cpp/src/lib/srwlib.h b/cpp/src/lib/srwlib.h index a7b59e0a..5d90e0a4 100644 --- a/cpp/src/lib/srwlib.h +++ b/cpp/src/lib/srwlib.h @@ -241,6 +241,7 @@ struct SRWLStructRadMesh { long ne, nx, ny; /* numbers of points vs photon energy, horizontal and vertical positions */ double nvx, nvy, nvz, hvx, hvy, hvz; /* lab-frame coordinate of the inner normal to observation plane (/ surface in its center) and horizontal base vector of the observation plane (/ surface in its center) */ double *arSurf; /* array defining the observation surface (as function of 2 variables - x & y - on the mesh given by _xStart, _xFin, _nx, _yStart, _yFin, _ny; to be used in case this surface differs from plane) */ + char type; /* type of data: 0- standard intensity, 'm'- mutual intensity //OC13112018 */ }; typedef struct SRWLStructRadMesh SRWLRadMesh; @@ -513,6 +514,13 @@ typedef struct SRWLStructOpticsContainer SRWLOptC; */ EXP void CALL srwlUtiSetWfrModifFunc(int (*pExtFunc)(int action, SRWLWfr* pWfrIn, char pol)); +/** + * Sets pointer to external function which allocates an array (continious memory block) in client environment. + * @param [in] pExtFunc pointer to the external function + * @see ... + */ +EXP void CALL srwlUtiSetAllocArrayFunc(char* (*pExtFunc)(char type, long long len)); //OC15082018 + /** * Sets pointer to external function to show progress of computation process * @param [in] pExtFunc pointer to the external function @@ -732,7 +740,8 @@ EXP int CALL srwlSetRepresElecField(SRWLWfr* pWfr, char repr); * @return integer error (>0) or warnig (<0) code * @see ... */ -EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt); +EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt, int nInt=0, char** arID=0, SRWLRadMesh* arIM=0, char** arI=0); //OC15082018 +//EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt); /** TEST * "Propagates" multple Electric Field Wavefronts from different electrons through Optical Elements and free spaces @@ -786,6 +795,39 @@ EXP int CALL srwlUtiFFT(char* pcData, char typeData, double* arMesh, int nMesh, */ EXP int CALL srwlUtiConvWithGaussian(char* pcData, char typeData, double* arMesh, int nMesh, double* arSig); +/** + * Calculates basic statistical characteristics of intensity distribution + * @param [in, out] arInf (double) array of characteristics to be extracted: + * arInf[0]: peak (max.) intensity + * arInf[1]: position of peak intensity vs 1st dimension + * arInf[2]: position of peak intensity vs 2nd dimension + * arInf[3]: position of peak intensity vs 3rd dimension (reserved for future use) + * arInf[4]: FWHM value of intensity distribution vs 1st dimension + * arInf[5]: FWHM value of intensity distribution vs 2nd dimension + * arInf[6]: FWHM value of intensity distribution vs 3rd dimension (reserved for future use) + * @param [in] pcData (char) pointer to intensity distribution data to be analyzed + * @param [in] typeData character specifying data type ('f' for float, 'd' for double) + * @param [in] pMesh (pointer to SRWLRadMesh) mesh of intensity data to be analyzed + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiIntInf(double* arInf, char* pcData, char typeData, SRWLRadMesh* pMesh); + +/** + * Performs misc. operations on intensity distribution (or similar C-aligned) arrays + * @param [in, out] pcI1 (char) pointer to intensity distribution data #1 + * @param [in] typeI1 character specifying intensity #1 data type ('f' for float, 'd' for double) + * @param [in] pMesh1 (pointer to SRWLRadMesh) mesh of intensity data #1 + * @param [in] pcI2 (char) pointer to intensity distribution data #2 + * @param [in] typeI2 character specifying intensity #2 data type ('f' for float, 'd' for double) + * @param [in] pMesh2 (pointer to SRWLRadMesh) mesh of intensity data #2 + * @param [in] arPar array of parameters defining operation to be performed: + * arPar[0] defines type of the operation, with the meaning of other elements dependent on it + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiIntProc(char* pcI1, char typeI1, SRWLRadMesh* pMesh1, char* pcI2, char typeI2, SRWLRadMesh* pMesh2, double* arPar); + /** * Attempts to deduce parameters of peridic undulator magnetic field from tabulated field and set up Undulator structure * @param [in, out] pUndCnt pointer to magnetic field container structure with undulator structure to be set up @@ -817,6 +859,12 @@ EXP int CALL srwlUtiUndFromMagFldTab(SRWLMagFldC* pUndCnt, SRWLMagFldC* pMagCnt, */ EXP int CALL srwlUtiUndFindMagFldInterpInds(int* arResInds, int* pnResInds, double* arGaps, double* arPhases, int nVals, double arPrecPar[5]); +/** + * These functions were added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP +EXP void CALL srwlPrintTime(const char* str, double* start); +EXP void CALL get_walltime(double* wcTime); + */ + /***************************************************************************/ #ifdef __cplusplus diff --git a/cpp/vc/SRW.sln b/cpp/vc/SRW.sln index c84ac92e..448cca38 100644 --- a/cpp/vc/SRW.sln +++ b/cpp/vc/SRW.sln @@ -43,8 +43,8 @@ Global {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Debug|x64.Build.0 = Debug_Py3_6|x64 {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Mixed Platforms.ActiveCfg = Release_Py3_3|Win32 {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Mixed Platforms.Build.0 = Release_Py3_3|Win32 - {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Win32.ActiveCfg = Release_Py2x|Win32 - {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Win32.Build.0 = Release_Py2x|Win32 + {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Win32.ActiveCfg = Release_Py3_6|Win32 + {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|Win32.Build.0 = Release_Py3_6|Win32 {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|x64.ActiveCfg = Release_Py3_6|x64 {B04ABD04-7AC6-4516-B8A7-E2CBC18B4333}.Release|x64.Build.0 = Release_Py3_6|x64 {0D473386-2B3E-4586-8516-DD4DCF6D4E1E}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 diff --git a/cpp/vc/SRWLClientC.vcxproj b/cpp/vc/SRWLClientC.vcxproj index 97e71f72..3d27b897 100644 --- a/cpp/vc/SRWLClientC.vcxproj +++ b/cpp/vc/SRWLClientC.vcxproj @@ -9,6 +9,14 @@ Debug x64 + + ReleaseOMP + Win32 + + + ReleaseOMP + x64 + Release Win32 @@ -47,6 +55,12 @@ v141 Unicode + + v141 + + + v141 + diff --git a/cpp/vc/SRWLClientIgor.vcxproj b/cpp/vc/SRWLClientIgor.vcxproj index 8c855f14..e1aa576e 100644 --- a/cpp/vc/SRWLClientIgor.vcxproj +++ b/cpp/vc/SRWLClientIgor.vcxproj @@ -9,6 +9,14 @@ Debug x64 + + ReleaseOMP + Win32 + + + ReleaseOMP + x64 + Release Win32 @@ -47,6 +55,12 @@ false MultiByte + + v141 + + + v141 + diff --git a/cpp/vc/SRWLClientPython.vcxproj.user b/cpp/vc/SRWLClientPython.vcxproj.user index 611b1524..a3cd212d 100644 --- a/cpp/vc/SRWLClientPython.vcxproj.user +++ b/cpp/vc/SRWLClientPython.vcxproj.user @@ -14,7 +14,7 @@ C:\SoftwareDevelopments\Python36_x64\python.exe - cox_test_02.py + chx_small_beam_saxs_texture_oc.py ..\..\env\work\srw_python WindowsLocalDebugger @@ -33,13 +33,13 @@ C:\SoftwareDevelopments\Python36_x64\python.exe WindowsLocalDebugger - SRWLIB_Example14.py + cdi-first-mirrors-close-10-um.py ..\..\env\work\srw_python C:\SoftwareDevelopments\Python27_x64\python.exe WindowsLocalDebugger - tabulated_undulator_example.py + cdi_optim_test_01.py ..\..\env\work\srw_python \ No newline at end of file diff --git a/cpp/vc/SRWLIB.vcxproj b/cpp/vc/SRWLIB.vcxproj index 37911cde..5385c1e8 100644 --- a/cpp/vc/SRWLIB.vcxproj +++ b/cpp/vc/SRWLIB.vcxproj @@ -9,6 +9,14 @@ Debug x64 + + ReleaseOMP + Win32 + + + ReleaseOMP + x64 + Release Win32 @@ -30,6 +38,12 @@ false MultiByte + + StaticLibrary + v141 + false + MultiByte + StaticLibrary v141 @@ -42,6 +56,12 @@ false MultiByte + + StaticLibrary + v141 + false + MultiByte + StaticLibrary v141 @@ -55,6 +75,10 @@ + + + + @@ -63,6 +87,10 @@ + + + + @@ -86,12 +114,23 @@ $(Platform)\$(Configuration)\ srw_win32 + + $(SolutionDir) + $(Platform)\$(Configuration)\ + srw_win32 + $(SolutionDir) $(Platform)\$(Configuration)\ true srw_x64 + + $(SolutionDir) + $(Platform)\$(Configuration)\ + true + srw_x64 + _DEBUG;%(PreprocessorDefinitions) @@ -206,6 +245,46 @@ copy $(TargetPath) "$(SolutionDir)..\..\env\work\srw_python\lib\" + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/SRWLIB.tlb + + + OnlyExplicitInline + Neither + ..\src\lib;..\src\core;..\src\ext\genmath;..\src\ext\auxparse;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;_USRDLL;__VC__;SRWLIB_STATIC;_GM_WITHOUT_BASE;_CRT_SECURE_NO_WARNINGS;NON_UNIX_STDIO;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + + + + + $(IntDir) + $(IntDir)vc90.pdb + Level3 + true + Default + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + ..\..\ext_lib\fftw_f.lib;%(AdditionalDependencies) + srw_win32.lib + + + copy $(TargetPath) "$(SolutionDir)..\..\env\work\srw_python\lib\" + + NDEBUG;%(PreprocessorDefinitions) @@ -250,6 +329,54 @@ copy $(SolutionDir)$(TargetName)$(TargetExt) "$(SolutionDir)..\..\env\work\srw_python\lib\" + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + .\Release/SRWLIB.tlb + + + OnlyExplicitInline + Speed + ..\src\lib;..\src\core;..\src\ext\genmath;..\src\ext\auxparse;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;_USRDLL;__VC__;SRWLIB_STATIC;_GM_WITHOUT_BASE;_WITH_OMP;_CRT_SECURE_NO_WARNINGS;NON_UNIX_STDIO;%(PreprocessorDefinitions) + true + MultiThreaded + false + true + + + + + $(IntDir) + $(IntDir)vc90.pdb + Level3 + true + + + Default + true + MaxSpeed + true + Precise + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + ..\..\ext_lib\fftw64_f.lib;%(AdditionalDependencies) + srw_x64.lib + + + + + copy $(SolutionDir)$(TargetName)$(TargetExt) "$(SolutionDir)..\..\env\work\srw_python\lib\" + + diff --git a/env/release/srw_python/Dependency.txt b/env/release/srw_python/Dependency.txt new file mode 100644 index 00000000..0cb889af --- /dev/null +++ b/env/release/srw_python/Dependency.txt @@ -0,0 +1,21 @@ +SRW for Python requires: +- Python 2.7 or 3.2/3.3/3.5/3.6 (64-bit or 32-bit) +- numpy +- matplotlib + +On Debian like (using Python 2.7): +sudo apt-get install python python-numpy python-matplotlib + +On Mac, install macports from http://www.macports.org/install.php then: +port install py27 py27-numpy py27-matplotlib + +Remeber to use the installed Python, which may be not the default python of the system. + +On Windows install Python MS Windows Installer from http://www.python.org/getit/ +and numpy and matplotlib from the binary files http://www.lfd.uci.edu/~gohlke/pythonlibs/ +Follow the instructions on the website to correctly install all the necessary dependencies. +On Windows, Python can be also installed together with Visual Studio 2017. + +The dependencies (numpy and matplotlib) can also installed using "pip" (at least for Python 3.4 or later).. +The use of 64-bit versions is preferable. + diff --git a/env/release/srw_python/ReadMe.txt b/env/release/srw_python/ReadMe.txt index 658ebf48..a7f46dfd 100644 --- a/env/release/srw_python/ReadMe.txt +++ b/env/release/srw_python/ReadMe.txt @@ -1,22 +1,22 @@ -Comments to "SRWLIB" for Python v. 0.06x (December 2012) +Comments to "SRWLIB" for Python (November 2017) ==================================================== Basic content and installation of the SRWLIB package: ---------------------------------------------------- - srwlpy.pyd, srwlpy.so are SRW Python bindings (shared libraries) compiled for Windows and Linux respectively. Note that there is no guarantee that these files, located in ../srw_python/, are compatible with the versions of operating system and Python that you are using. -The compiled shared library files for Python 3.2 and 2.7 for 64- and 32-bit Windows and Linux are available in ../srw_python/lib/. The file names of the compiled shared libraries are self-explanatory: e.g. srwlpy3_x64.pyd is a version for Python 3.2 for Windows 64-bit; srwlpy2_i686.so is for Python 2.7 for Linux 32-bit. Copy the compiled shared library file corresponding to your operating system and Python versions from ../srw_python/lib/ to ../srw_python/ and change its name to srwlpy.pyd (on Windows) or srwlpy.so (on Linux) e.g.: +The compiled shared library files for Python 3.x and 2.7 for 64- and 32-bit Windows and Linux are available in ../srw_python/lib/. The file names of the compiled shared libraries are self-explanatory: e.g. srwlpy3_6_x64.pyd is a version for Python 3.6 for Windows 64 bit; srwlpy2_7_x86_64.so is for Python 2.7 for Linux 64 bit. Copy the compiled shared library file corresponding to your operating system and Python versions from ../srw_python/lib/ to ../srw_python/ and change its name to srwlpy.pyd (on Windows) or srwlpy.so (on Linux) e.g.: on Windows: -copy ..\srw_python\lib\srwlpy3_x64.pyd ..\srw_python\srwlpy.pyd +copy ..\srw_python\lib\srwlpy3_6_x64.pyd ..\srw_python\srwlpy.pyd on Linux: -cp ../srw_python/lib/srwlpy3_x86_64.so ../srw_python/srwlpy.so +cp ../srw_python/lib/srwlpy2_7_x86_64.so ../srw_python/srwlpy.so where ".." is the path to the srw_python folder. - srwlib.py is SRWLIB Python module definition file; it is compatible both with Python 3.2 (or higher) and 2.7 (or higher). - SRWLIB_Example*.py files are SRWLIB Python example scripts, which are also compatible with Python 3.2 and 2.7. -- ../srw_python/lib/srw*.lib, ../srw_python/lib/libsrw*.a are static SRW libraries (C API) compiled for 32- (srw_win32.lib) and 64-bit (srw_x64.lib) Windows and 32-bit (libsrw_i686.a) and 64-bit (libsrw_x86_64.a) Linux. These files may not be necessary for the SRWLIB for Python (because *.pyd and *.so files should normally contain these static libraries linked). +- ../srw_python/lib/srw*.lib, ../srw_python/lib/libsrw*.a are static SRW libraries (C API) compiled for 32- (srw_win32.lib) and 64-bit (srw_x64.lib) Windows and 64-bit Linux (libsrw_x86_64.a). These files may not be necessary for the SRWLIB for Python (because *.pyd and *.so files should normally contain these static libraries linked). - ../srw_python/lib/srwlib.h is the header file of SRW C API (it defines C structures and declares functions of SRWLIB). @@ -33,8 +33,8 @@ The examples may read some input (ASCII) files and save some output (also mostly Optional configuring of Python and SRWLIB on Linux: ---------------------------------------------------- -Make sure that path to Python 3.2 (or 2.7) is added to the PATH variable and "srw_python" directory to PYTHONPATH variable: -export PATH="$PATH:" #this is not necessary if you install python using the distro's package manager +Make sure that path to Python 3.6 (or 2.7) is added to the PATH variable and "srw_python" directory to PYTHONPATH variable: +export PATH="$PATH:" #this is not necessary if you install python using the distro's package manager export PYTHONPATH="$PYTHONPATH:SRW_Dev/work/srw_python/" #temporarely solution or: echo "export PYTHONPATH=$PYTHONPATH:SRW_Dev/work/srw_python/" >> ~/.bashrc # permanent solution for a single user diff --git a/env/release/srw_python/SRWLIB_Example01.py b/env/release/srw_python/SRWLIB_Example01.py index fc7073b3..c483b606 100644 --- a/env/release/srw_python/SRWLIB_Example01.py +++ b/env/release/srw_python/SRWLIB_Example01.py @@ -1,10 +1,12 @@ +# -*- coding: utf-8 -*- ############################################################################# # SRWLIB Example#1: Calculating electron trajectory in 3D magnetic field of an APPLE-II undulator -# v 0.03 +# v 0.06 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 1:') @@ -70,20 +72,7 @@ def AuxReadInMagFld3D(filePath, sCom): if yNp > 1: yRange = (yNp - 1)*yStep zRange = zStep if zNp > 1: zRange = (zNp - 1)*zStep - return SRWLMagFld3D(locArBx, locArBy, locArBz, xNp, yNp, zNp, xStep*(xNp - 1), yStep*(yNp - 1), zStep*(zNp - 1), 1) - -#**********************Auxiliary function to write tabulated resulting Trajectory data to ASCII file: -def AuxSaveTrajData(traj, filePath): - f = open(filePath, 'w') - f.write('#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]\n') - ctStep = 0 - if traj.np > 0: - ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) - ct = traj.ctStart - for i in range(traj.np): - f.write(str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + '\n') - ct += ctStep - f.close() + return SRWLMagFld3D(locArBx, locArBy, locArBz, xNp, yNp, zNp, xRange, yRange, zRange, 1) #**********************Defining Magnetic Field: magFldCnt = SRWLMagFldC() #Container @@ -113,7 +102,8 @@ def AuxSaveTrajData(traj, filePath): #**********************Trajectory structure, where the results will be stored partTraj = SRWLPrtTrj() partTraj.partInitCond = part -partTraj.allocate(npTraj) +#partTraj.allocate(npTraj) +partTraj.allocate(npTraj, True) partTraj.ctStart = 0 #Start Time for the calculation #partTraj.ctEnd = (numPer + 2)*per + magFldCnt.arMagFld[0].rz + magFldCnt.arMagFld[2].rz #End Time partTraj.ctEnd = magFldCnt.arMagFld[0].rz @@ -123,7 +113,20 @@ def AuxSaveTrajData(traj, filePath): partTraj = srwl.CalcPartTraj(partTraj, magFldCnt, arPrecPar) print('done') -#**********************Saving results +#**********************Saving results to a file print(' Saving trajectory data to a file ... ', end='') -AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strTrajOutFileName)) +partTraj.save_ascii(os.path.join(os.getcwd(), strExDataFolderName, strTrajOutFileName)) +print('done') + +#**********************Plotting results +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +ctMesh = [partTraj.ctStart, partTraj.ctEnd, partTraj.np] +for i in range(partTraj.np): + partTraj.arX[i] *= 1000 + partTraj.arY[i] *= 1000 + +uti_plot1d(partTraj.arX, ctMesh, ['ct [m]', 'Horizontal Position [mm]']) +uti_plot1d(partTraj.arY, ctMesh, ['ct [m]', 'Vertical Position [mm]']) + +uti_plot_show() #show all graphs (and block execution) print('done') diff --git a/env/release/srw_python/SRWLIB_Example01_kick_matr.py b/env/release/srw_python/SRWLIB_Example01_kick_matr.py index 0fdb85c6..89431a21 100644 --- a/env/release/srw_python/SRWLIB_Example01_kick_matr.py +++ b/env/release/srw_python/SRWLIB_Example01_kick_matr.py @@ -1,10 +1,11 @@ ############################################################################# # SRWLIB Example#1: Calculating electron trajectory in 3D magnetic field of an APPLE-II undulator -# v 0.03 +# v 0.06 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 1:') @@ -123,19 +124,6 @@ def AuxReadInMagFld3D(filePath, sCom): if zNp > 1: zRange = (zNp - 1)*zStep return SRWLMagFld3D(locArBx, locArBy, locArBz, xNp, yNp, zNp, xStep*(xNp - 1), yStep*(yNp - 1), zStep*(zNp - 1), 1) -#**********************Auxiliary function to write tabulated resulting Trajectory data to ASCII file: -def AuxSaveTrajData(traj, filePath): - f = open(filePath, 'w') - f.write('#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]\n') - ctStep = 0 - if traj.np > 0: - ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) - ct = traj.ctStart - for i in range(traj.np): - f.write(str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + '\n') - ct += ctStep - f.close() - #**********************Input Parameters and Input/Output structures: partTraj = SRWLPrtTrj() #Central Trajectory partTraj.partInitCond.x = 0 #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] @@ -190,14 +178,30 @@ def AuxSaveTrajData(traj, filePath): print(' Performing calculation ... ', end='') srwl.CalcPartTraj(partTraj, magFldCnt, arPrecTrajFromField) #First Calculate Central Trajectory -AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strCenTrajOutFileName)) +partTraj.save_ascii(os.path.join(os.getcwd(), strExDataFolderName, strCenTrajOutFileName)) partTraj.partInitCond.x = newInitCondX partTraj.partInitCond.y = newInitCondY srwl.CalcPartTrajFromKickMatr(partTraj, kickMatr, arPrecTrajFromKickM)#Calculate Off-Axis Trajectory using Kick-Matrix method -AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strOffKickTrajOutFileName)) +partTraj.save_ascii(os.path.join(os.getcwd(), strExDataFolderName, strOffKickTrajOutFileName)) srwl.CalcPartTraj(partTraj, magFldCnt, arPrecTrajFromField) #Calculate same Off-Axis Trajectory by Runge-Kutta integration in 3D Magnetic Field -AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strOffTrajOutFileName)) +partTraj.save_ascii(os.path.join(os.getcwd(), strExDataFolderName, strOffTrajOutFileName)) + +print('done') +#**********************Plotting results +print(' Plotting the results (close all graph windows to proceed with the script execution) ... ', end='') +ctMesh = [partTraj.ctStart, partTraj.ctEnd, partTraj.np] +for i in range(partTraj.np): #converting from [m] to [mm] and from [rad] to [mrad] + partTraj.arX[i] *= 1000 + partTraj.arXp[i] *= 1000 + partTraj.arY[i] *= 1000 + partTraj.arYp[i] *= 1000 + +uti_plot1d(partTraj.arX, ctMesh, ['ct [m]', 'Horizontal Position [m]m']) +uti_plot1d(partTraj.arXp, ctMesh, ['ct [m]', 'Horizontal Angle [mrad]']) +uti_plot1d(partTraj.arY, ctMesh, ['ct [m]', 'Vertical Position [mm]']) +uti_plot1d(partTraj.arYp, ctMesh, ['ct [m]', 'Vertical Angle [mrad]']) +uti_plot_show() print('done') diff --git a/env/release/srw_python/SRWLIB_Example02.py b/env/release/srw_python/SRWLIB_Example02.py index 1e976c66..e46d54b5 100644 --- a/env/release/srw_python/SRWLIB_Example02.py +++ b/env/release/srw_python/SRWLIB_Example02.py @@ -1,26 +1,23 @@ ############################################################################# # SRWLIB Example#2: Calculating electron trajectory in magnetic field of a segmented planar undulator -# v 0.03 +# v 0.07 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 2:') print('Calculating electron trajectory in magnetic field of a segmented planar undulator with FODO lattice') -#**********************Input Parameters: +#**********************Input Parameters +#**********************Folder and File names strExDataFolderName = 'data_example_02' #example data sub-folder name +strFldOutFileName = 'ex02_res_fld.dat' #file name for output (tabulated) magnetic field data strTrajOutFileName = 'ex02_res_traj.dat' #file name for output trajectory data -numSegm = 5 #Number of ID Segments -numPer = 100 #Number of Periods in one Segment (without counting for terminations) -undPer = 0.02 #Period Length [m] -xcID = 0 #Transverse Coordinates of ID Center [m] -ycID = 0 -zcID = 0 #Longitudinal Coordinate of ID Center [m] - +#**********************Initial Conditions for Particle Trajectory Calculation part = SRWLParticle() part.x = 0.0001 #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] part.y = 0.0001 @@ -40,6 +37,14 @@ #[6]: tolerance (default = 1) for R-K fifth order or higher #[7]: max. number of auto-steps for R-K fifth order or higher (default = 5000) +#**********************Magnetic Field +numSegm = 5 #Number of ID Segments +numPer = 100 #Number of Periods in one Segment (without counting for terminations) +undPer = 0.02 #Period Length [m] +xcID = 0 #Transverse Coordinates of ID Center [m] +ycID = 0 +zcID = 0 #Longitudinal Coordinate of ID Center [m] + und = SRWLMagFldU([SRWLMagFldH(1, 'v', 1.05, 0, 1)], undPer, numPer) #Undulator Segment qf = SRWLMagFldM(0.5, 2, 'n', 0.2) #Focusing Quad qd = SRWLMagFldM(-0.5, 2, 'n', 0.2) #Defocusing Quad @@ -53,35 +58,140 @@ part.z = arZc[0] - 0.5*undLenExt #Initial Longitudinal Coordinate (set before the ID) -#**********************Auxiliary function to write tabulated resulting Trajectory data to ASCII file: -def AuxSaveTrajData(traj, filePath): - f = open(filePath, 'w') - f.write('#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]\n') - #print('file opened: ', filePath) - ctStep = 0 - if traj.np > 0: - ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) - ct = traj.ctStart - for i in range(traj.np): - f.write(str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + '\n') - ct += ctStep - f.close() +print(' Tabulating Magnetic Field for display ... ', end='') +dispBy = array('d', [0]*npTraj) +dispMagFld3D = SRWLMagFld3D(_arBy=dispBy, _nx=1, _ny=1, _nz=npTraj, _rz=5*undLenExt) +xDisp = part.x +yDisp = part.y +dispMagFldCnt = SRWLMagFldC([dispMagFld3D], array('d', [xDisp]), array('d', [yDisp]), array('d', [0])) +srwl.CalcMagnField(dispMagFldCnt, magFldCnt) +print('done') #**********************Trajectory structure, where the results will be stored partTraj = SRWLPrtTrj() partTraj.partInitCond = part -partTraj.allocate(npTraj) +#partTraj.allocate(npTraj) +partTraj.allocate(npTraj, True) #True ensures that field along trajectory will also be extracted partTraj.ctStart = 0 #"Start Time" (c*t) for the calculation (0 corresponds to the time moment for which the initial conditions are defined) partTraj.ctEnd = partTraj.ctStart + 5*undLenExt #End Time -#**********************Calculation (SRWLIB function call) +#**********************Trajectory Calculation (SRWLIB function call) print(' Performing calculation ... ', end='') partTraj = srwl.CalcPartTraj(partTraj, magFldCnt, arPrecPar) print('done') #**********************Saving results +#Auxiliary function to write tabulated Magnetic Field data to ASCII file: +def AuxSaveMagFldData(dispFld3D, xc, yc, zc, filePath): + + hx = 0 if(dispFld3D.nx <= 1) else dispFld3D.rx/(dispFld3D.nx - 1) + hy = 0 if(dispFld3D.ny <= 1) else dispFld3D.ry/(dispFld3D.ny - 1) + hz = 0 if(dispFld3D.nz <= 1) else dispFld3D.rz/(dispFld3D.nz - 1) + + arXdef = False + if((dispFld3D.arX != None) and (len(dispFld3D.arX) == dispFld3D.nx)): + arXdef = True + arYdef = False + if((dispFld3D.arY != None) and (len(dispFld3D.arY) == dispFld3D.ny)): + arYdef = True + arZdef = False + if((dispFld3D.arZ != None) and (len(dispFld3D.arZ) == dispFld3D.nz)): + arZdef = True + + nTot = dispFld3D.nx*dispFld3D.ny*dispFld3D.nz + arBxDef = False + if((dispFld3D.arBx != None) and (len(dispFld3D.arBx) == nTot)): + arBxDef = True + arByDef = False + if((dispFld3D.arBy != None) and (len(dispFld3D.arBy) == nTot)): + arByDef = True + arBzDef = False + if((dispFld3D.arBz != None) and (len(dispFld3D.arBz) == nTot)): + arBzDef = True + + f = open(filePath, 'w') + resStr = '#X [m], Y [m], Z [m]' + if(arBxDef == True): + resStr += ', Bx [T]' + if(arByDef == True): + resStr += ', By [T]' + if(arBzDef == True): + resStr += ', Bz [T]' + f.write(resStr + '\n') + + i = 0 + z = zc - 0.5*dispFld3D.rz + for iz in range(dispFld3D.nz): + if(arZdef == True): + z = dispFld3D.arZ[iz] + zc + #print(z) + y = yc - 0.5*dispFld3D.ry + for iy in range(dispFld3D.ny): + if(arYdef == True): + y = dispFld3D.arY[iy] + yc + x = xc - 0.5*dispFld3D.rx + for ix in range(dispFld3D.nx): + if(arXdef == True): + x = dispFld3D.arX[ix] + xc + resStr = repr(x) + '\t' + repr(y) + '\t' + repr(z) + if(arBxDef == True): + resStr += '\t' + repr(dispFld3D.arBx[i]) + if(arByDef == True): + resStr += '\t' + repr(dispFld3D.arBy[i]) + if(arBzDef == True): + resStr += '\t' + repr(dispFld3D.arBz[i]) + f.write(resStr + '\n') + i += 1 + x += hx + y += hy + z += hz + f.close() + +#Auxiliary function to write tabulated resulting Trajectory data to ASCII file: +def AuxSaveTrajData(traj, filePath): + f = open(filePath, 'w') + resStr = '#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]' + if(hasattr(traj, 'arBx')): + resStr += ', Bx [T]' + if(hasattr(traj, 'arBy')): + resStr += ', By [T]' + if(hasattr(traj, 'arBz')): + resStr += ', Bz [T]' + f.write(resStr + '\n') + ctStep = 0 + if traj.np > 0: + ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) + ct = traj.ctStart + for i in range(traj.np): + resStr = str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + if(hasattr(traj, 'arBx')): + resStr += '\t' + repr(traj.arBx[i]) + if(hasattr(traj, 'arBy')): + resStr += '\t' + repr(traj.arBy[i]) + if(hasattr(traj, 'arBz')): + resStr += '\t' + repr(traj.arBz[i]) + f.write(resStr + '\n') + ct += ctStep + f.close() + print(' Saving trajectory data to a file ... ', end='') -#raw_input() +AuxSaveMagFldData(dispMagFld3D, 0, 0, 0, os.path.join(os.getcwd(), strExDataFolderName, strFldOutFileName)) AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strTrajOutFileName)) -#raw_input() +print('done') + +#**********************Plotting results +print(' Plotting the results (close all graph windows to proceed with the script execution) ... ', end='') +ctMesh = [partTraj.ctStart, partTraj.ctEnd, partTraj.np] +for i in range(partTraj.np): #converting from [m] to [mm] and from [rad] to [mrad] + partTraj.arXp[i] *= 1000 + partTraj.arX[i] *= 1000 + partTraj.arYp[i] *= 1000 + partTraj.arY[i] *= 1000 +uti_plot1d(partTraj.arBy, ctMesh, ['ct [m]', 'Vertical Magnetic Field [T]']) +uti_plot1d(partTraj.arXp, ctMesh, ['ct [m]', 'Horizontal Angle [mrad]']) +uti_plot1d(partTraj.arX, ctMesh, ['ct [m]', 'Horizontal Position [mm]']) +uti_plot1d(partTraj.arBx, ctMesh, ['ct [m]', 'Horizontal Magnetic Field [T]']) +uti_plot1d(partTraj.arYp, ctMesh, ['ct [m]', 'Vertical Angle [mrad]']) +uti_plot1d(partTraj.arY, ctMesh, ['ct [m]', 'Vertical Position [mm]']) +uti_plot_show() print('done') diff --git a/env/release/srw_python/SRWLIB_Example03.py b/env/release/srw_python/SRWLIB_Example03.py index 822a97b8..2a4fb278 100644 --- a/env/release/srw_python/SRWLIB_Example03.py +++ b/env/release/srw_python/SRWLIB_Example03.py @@ -1,10 +1,11 @@ ############################################################################# # SRWLIB Example#3: Calculating synchrotron (undulator) radiation emitted by an electron travelling in ellipsoidal undulator -# v 0.04 +# v 0.07 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 3:') @@ -47,9 +48,10 @@ relPrec = 0.01 #relative precision zStartInteg = 0 #longitudinal position to start integration (effective if < zEndInteg) zEndInteg = 0 #longitudinal position to finish integration (effective if > zStartInteg) -npTraj = 20000 +npTraj = 20000 #Number of points for trajectory calculation +useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) sampFactNxNyForProp = 0 #sampling factor for adjusting nx, ny (effective if > 0) -arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, 0, sampFactNxNyForProp] +arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] #***********Wavefront wfr1 = SRWLWfr() #For spectrum vs photon energy @@ -75,23 +77,6 @@ wfr2.mesh.yFin = 0.001 #Final Vertical Position [m] wfr2.partBeam = elecBeam -#**********************Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() - #**********************Calculation (SRWLIB function calls) print(' Performing Electric Field (spectrum vs photon energy) calculation ... ', end='') srwl.CalcElecFieldSR(wfr1, 0, magFldCnt, arPrecPar) @@ -108,8 +93,25 @@ def AuxSaveIntData(arI, mesh, filePath): srwl.CalcIntFromElecField(arI2, wfr2, 6, 0, 3, wfr2.mesh.eStart, 0, 0) print('done') -#**********************Saving results +#**********************Saving results to files print(' Saving intensity data to files ... ', end='') -AuxSaveIntData(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) -AuxSaveIntData(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) +srwl_uti_save_intens_ascii(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1), 0) +srwl_uti_save_intens_ascii(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2), 0) +print('done') + +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +uti_plot1d(arI1, [wfr1.mesh.eStart, wfr1.mesh.eFin, wfr1.mesh.ne], ['Photon Energy [eV]', 'Intensity [ph/s/.1%bw/mm^2]', 'On-Axis Spectrum']) +uti_plot2d(arI2, [1000*wfr2.mesh.xStart, 1000*wfr2.mesh.xFin, wfr2.mesh.nx], [1000*wfr2.mesh.yStart, 1000*wfr2.mesh.yFin, wfr2.mesh.ny], ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV']) + +arI2x = array('f', [0]*wfr2.mesh.nx) #array to take 1D intensity data (vs X) +srwl.CalcIntFromElecField(arI2x, wfr2, 6, 0, 1, wfr2.mesh.eStart, 0, 0) +uti_plot1d(arI2x, [1000*wfr2.mesh.xStart, 1000*wfr2.mesh.xFin, wfr2.mesh.nx], ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV\n(horizontal cut at x = 0)']) + +arI2y = array('f', [0]*wfr2.mesh.ny) #array to take 1D intensity data (vs Y) +srwl.CalcIntFromElecField(arI2y, wfr2, 6, 0, 2, wfr2.mesh.eStart, 0, 0) +uti_plot1d(arI2y, [1000*wfr2.mesh.yStart, 1000*wfr2.mesh.yFin, wfr2.mesh.ny], ['Vertical Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV\n(vertical cut at y = 0)']) + +uti_plot_show() #show all graphs (and block execution) print('done') + diff --git a/env/release/srw_python/SRWLIB_Example04.py b/env/release/srw_python/SRWLIB_Example04.py index e9781b0e..4f926e3c 100644 --- a/env/release/srw_python/SRWLIB_Example04.py +++ b/env/release/srw_python/SRWLIB_Example04.py @@ -1,11 +1,12 @@ ############################################################################# # SRWLIB Example#4: Calculating synchrotron (undulator) radiation electric field (from one electron) # and simulating wavefront propagation through a simple optical system -# v 0.03 +# v 0.06 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 4:') @@ -47,16 +48,17 @@ relPrec = 0.01 #relative precision zStartInteg = 0 #longitudinal position to start integration (effective if < zEndInteg) zEndInteg = 0 #longitudinal position to finish integration (effective if > zStartInteg) -npTraj = 20000 +npTraj = 20000 #Number of points for trajectory calculation +useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) sampFactNxNyForProp = 1 #sampling factor for adjusting nx, ny (effective if > 0) -arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, 0, sampFactNxNyForProp] +arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] #***********Initial Wavefront wfr = SRWLWfr() wfr.allocate(1, 100, 100) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions (may be modified by the library!) wfr.mesh.zStart = 20. #Longitudinal Position [m] at which SR has to be calculated -wfr.mesh.eStart = 1090. #Initial Photon Energy [eV] -wfr.mesh.eFin = 1090. #Final Photon Energy [eV] +wfr.mesh.eStart = 1095. #1090. #Initial Photon Energy [eV] +wfr.mesh.eFin = 1095. #1090. #Final Photon Energy [eV] wfr.mesh.xStart = -0.001 #Initial Horizontal Position [m] wfr.mesh.xFin = 0.001 #Final Horizontal Position [m] wfr.mesh.yStart = -0.001 #Initial Vertical Position [m] @@ -87,37 +89,68 @@ optBL = SRWLOptC([optLens, optDrift], [propagParLens, propagParDrift]) #"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) #**********************Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() +#replaced by srwlib.srwl_uti_save_intens_ascii +#def AuxSaveIntData(arI, mesh, filePath): +# f = open(filePath, 'w') +# f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') +# f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') +# f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') +# f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') +# f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') +# f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') +# f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') +# f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') +# f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') +# f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') +# for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array +# f.write(' ' + repr(arI[i]) + '\n') +# f.close() #**********************Calculation (SRWLIB function calls) and post-processing print(' Performing Initial Electric Field calculation ... ', end='') srwl.CalcElecFieldSR(wfr, 0, magFldCnt, arPrecPar) print('done') -print(' Extracting Intensity from calculated Initial Electric Field and saving it to file ... ', end='') -arI0 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data -srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) -AuxSaveIntData(arI0, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) +print(' Extracting Intensity from calculated Initial Electric Field and saving it to a file ... ', end='') +mesh0 = deepcopy(wfr.mesh) +arI0 = array('f', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D intensity data +srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, mesh0.eStart, 0, 0) +#AuxSaveIntData(arI0, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) +srwl_uti_save_intens_ascii(arI0, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1), 0) + +arI0x = array('f', [0]*mesh0.nx) #array to take 1D intensity data (vs X) +srwl.CalcIntFromElecField(arI0x, wfr, 6, 0, 1, mesh0.eStart, 0, 0) +arI0y = array('f', [0]*mesh0.ny) #array to take 1D intensity data (vs Y) +srwl.CalcIntFromElecField(arI0y, wfr, 6, 0, 2, mesh0.eStart, 0, 0) print('done') print(' Simulating Electric Field Wavefront Propagation ... ', end='') srwl.PropagElecField(wfr, optBL) print('done') print(' Extracting Intensity from propagated Electric Field and saving it to files ... ', end='') -arI1 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" 2D array to take intensity data -srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) -AuxSaveIntData(arI1, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) +mesh1 = deepcopy(wfr.mesh) +arI1 = array('f', [0]*mesh1.nx*mesh1.ny) #"flat" 2D array to take intensity data +srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, mesh1.eStart, 0, 0) +#AuxSaveIntData(arI1, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) +srwl_uti_save_intens_ascii(arI1, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2), 0) + +arI1x = array('f', [0]*mesh1.nx) #array to take 1D intensity data (vs X) +srwl.CalcIntFromElecField(arI1x, wfr, 6, 0, 1, mesh1.eStart, 0, 0) +arI1y = array('f', [0]*mesh1.ny) #array to take 1D intensity data (vs Y) +srwl.CalcIntFromElecField(arI1y, wfr, 6, 0, 2, mesh1.eStart, 0, 0) +print('done') + +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +plotMesh0x = [1000*mesh0.xStart, 1000*mesh0.xFin, mesh0.nx] +plotMesh0y = [1000*mesh0.yStart, 1000*mesh0.yFin, mesh0.ny] +uti_plot2d(arI0, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity Before Propagation']) +uti_plot1d(arI0x, plotMesh0x, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity Before Propagation\n(hor. cut at y = 0)']) +uti_plot1d(arI0y, plotMesh0y, ['Vertical Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity Before Propagation\n(vert. cut at x = 0)']) + +plotMesh1x = [1000*mesh1.xStart, 1000*mesh1.xFin, mesh1.nx] +plotMesh1y = [1000*mesh1.yStart, 1000*mesh1.yFin, mesh1.ny] +uti_plot2d(arI1, plotMesh1x, plotMesh1y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity After Propagation']) +uti_plot1d(arI1x, plotMesh1x, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity After Propagation\n(hor. cut at y = 0)']) +uti_plot1d(arI1y, plotMesh1y, ['Vertical Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity After Propagation\n(vert. cut at x = 0)']) +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) print('done') diff --git a/env/release/srw_python/SRWLIB_Example05.py b/env/release/srw_python/SRWLIB_Example05.py index 96b4e30e..d276eb17 100644 --- a/env/release/srw_python/SRWLIB_Example05.py +++ b/env/release/srw_python/SRWLIB_Example05.py @@ -1,11 +1,12 @@ -########################################################################### +############################################################################# # SRWLIB Example#5: Calculating electron trajectory and spontaneous emission # from a very long segmented undulator (transversely-uniform magnetic field defined) -# v 0.04 (based on tests of G. Geloni) +# v 0.07 (based on tests of G. Geloni) ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os print('SRWLIB Python Example # 5:') @@ -52,32 +53,47 @@ def AuxReadInMagFld3D(filePath, sCom): #**********************Auxiliary function to write tabulated resulting Trajectory data to ASCII file: def AuxSaveTrajData(traj, filePath): f = open(filePath, 'w') - f.write('#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]\n') + resStr = '#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]' + if(hasattr(traj, 'arBx')): + resStr += ', Bx [T]' + if(hasattr(traj, 'arBy')): + resStr += ', By [T]' + if(hasattr(traj, 'arBz')): + resStr += ', Bz [T]' + f.write(resStr + '\n') ctStep = 0 if traj.np > 0: ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) ct = traj.ctStart for i in range(traj.np): - f.write(str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + '\n') + resStr = str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + if(hasattr(traj, 'arBx')): + resStr += '\t' + repr(traj.arBx[i]) + if(hasattr(traj, 'arBy')): + resStr += '\t' + repr(traj.arBy[i]) + if(hasattr(traj, 'arBz')): + resStr += '\t' + repr(traj.arBz[i]) + f.write(resStr + '\n') ct += ctStep f.close() #**********************Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() +#replaced by srwlib.srwl_uti_save_intens_ascii +#def AuxSaveIntData(arI, mesh, filePath): +# f = open(filePath, 'w') +# f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') +# f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') +# f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') +# f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') +# f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') +# f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') +# f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') +# f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') +# f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') +# f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') +# for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array +# f.write(' ' + repr(arI[i]) + '\n') +# f.close() #**********************Defining Magnetic Field: xcID = 0 #Transverse Coordinates of ID Center [m] @@ -95,7 +111,7 @@ def AuxSaveIntData(arI, mesh, filePath): magFldCnt.arZc[0] = zcID magFldCnt.arMagFld[0].nRep = 1 #Entire ID -#**********************Trajectory structure, where the results will be stored +#**********************Trajectory structure (where the results will be stored) part = SRWLParticle() part.x = 0.0 #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] part.y = 0.0 @@ -134,8 +150,9 @@ def AuxSaveIntData(arI, mesh, filePath): zStartInteg = 0 #-129.029 #part.z - 0.1 #longitudinal position to start integration (effective if < zEndInteg) zEndInteg = 0 #129.029 #part.z + 5.3 #longitudinal position to finish integration (effective if > zStartInteg) #* Already specified before : npTraj +useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) sampFactNxNyForProp = 0 #sampling factor for adjusting nx, ny (effective if > 0) -arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, 0, sampFactNxNyForProp] +arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] #**********************Wavefront wfr1 = SRWLWfr() #For spectrum vs photon energy @@ -180,7 +197,31 @@ def AuxSaveIntData(arI, mesh, filePath): #**********************Saving results print(' Saving intensity data to files ... ', end='') -AuxSaveIntData(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) -AuxSaveIntData(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) +#AuxSaveIntData(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) +srwl_uti_save_intens_ascii(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1), 0) +#AuxSaveIntData(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) +srwl_uti_save_intens_ascii(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2), 0) print('done') +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +ctMesh = [partTraj.ctStart, partTraj.ctEnd, partTraj.np] +for i in range(partTraj.np): partTraj.arY[i] *= 1000 +uti_plot1d(partTraj.arY, ctMesh, ['ct [m]', 'Vertical Position [mm]', 'Electron Trajectory']) + +uti_plot1d(arI1, [wfr1.mesh.eStart, wfr1.mesh.eFin, wfr1.mesh.ne], ['Photon Energy [eV]', 'Intensity [ph/s/.1%bw/mm^2]', 'On-Axis Spectrum']) + +plotMeshX = [1000*wfr2.mesh.xStart, 1000*wfr2.mesh.xFin, wfr2.mesh.nx] +plotMeshY = [1000*wfr2.mesh.yStart, 1000*wfr2.mesh.yFin, wfr2.mesh.ny] +uti_plot2d(arI2, plotMeshX, plotMeshY, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV']) + +arI2x = array('f', [0]*wfr2.mesh.nx) #array to take 1D intensity data +srwl.CalcIntFromElecField(arI2x, wfr2, 6, 0, 1, wfr2.mesh.eStart, 0, 0) +uti_plot1d(arI2x, plotMeshX, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV\n(horizontal cut at y = 0)']) + +arI2y = array('f', [0]*wfr2.mesh.ny) #array to take 1D intensity data +srwl.CalcIntFromElecField(arI2y, wfr2, 6, 0, 2, wfr2.mesh.eStart, 0, 0) +uti_plot1d(arI2y, plotMeshY, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity at ' + str(wfr2.mesh.eStart) + ' eV\n(vertical cut at x = 0)']) + +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) +print('done') diff --git a/env/release/srw_python/SRWLIB_Example06.py b/env/release/srw_python/SRWLIB_Example06.py index 0b9ec86e..46d8f39f 100644 --- a/env/release/srw_python/SRWLIB_Example06.py +++ b/env/release/srw_python/SRWLIB_Example06.py @@ -2,15 +2,16 @@ # SRWLIB Example#6: Calculating spectral flux of undulator radiation # by finite-emittance electron beam collected through a finite aperture # and power density distribution of this radiation (integrated over all photon energies) -# v 0.02 +# v 0.03 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * import os import sys -print('SRWLIB Python Example # 6:') +print('SRWLIB Extended Example # 6:') print('Calculating spectral flux of undulator radiation by finite-emittance electron beam collected through a finite aperture and power density distribution of this radiation (integrated over all photon energies)') #**********************Input Parameters: @@ -86,6 +87,22 @@ stkP.mesh.yStart = -0.015 #initial vertical position [m] stkP.mesh.yFin = 0.015 #final vertical position [m] +#stkPx = SRWLStokes() #for power density +#stkPx.allocate(1, 101, 1) #numbers of points vs horizontal and vertical positions (photon energy is not taken into account) +#stkPx.mesh.zStart = stkP.mesh.zStart #longitudinal position [m] at which power density has to be calculated +#stkPx.mesh.xStart = stkP.mesh.xStart #initial horizontal position [m] +#stkPx.mesh.xFin = stkP.mesh.xFin #final horizontal position [m] +#stkPx.mesh.yStart = 0 #initial vertical position [m] +#stkPx.mesh.yFin = 0 #final vertical position [m] + +#stkPy = SRWLStokes() #for power density +#stkPy.allocate(1, 1, 101) #numbers of points vs horizontal and vertical positions (photon energy is not taken into account) +#stkPy.mesh.zStart = stkP.mesh.zStart #longitudinal position [m] at which power density has to be calculated +#stkPy.mesh.xStart = 0 #initial horizontal position [m] +#stkPy.mesh.xFin = 0 #final horizontal position [m] +#stkPy.mesh.yStart = stkP.mesh.yStart #initial vertical position [m] +#stkPy.mesh.yFin = stkP.mesh.yFin #final vertical position [m] + #sys.exit(0) #**********************Calculation (SRWLIB function calls) @@ -106,44 +123,38 @@ print(' Performing Power Density calculation (from field) ... ', end='') srwl.CalcPowDenSR(stkP, eBeam, 0, magFldCnt, arPrecP) +#srwl.CalcPowDenSR(stkPx, eBeam, 0, magFldCnt, arPrecP) +#srwl.CalcPowDenSR(stkPy, eBeam, 0, magFldCnt, arPrecP) print('done') #**********************Saving results -#Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def AuxSaveS0Data(stk, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(stk.mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(stk.mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(stk.mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(stk.mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(stk.mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(stk.mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(stk.mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(stk.mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(stk.mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(stk.mesh.ne*stk.mesh.nx*stk.mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(stk.arS[i]) + '\n') - f.close() - -#Auxiliary function to write tabulated Trajectory data to ASCII file: -def AuxSaveTrajData(traj, filePath): - f = open(filePath, 'w') - f.write('#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [m]\n') - ctStep = 0 - if traj.np > 0: - ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) - ct = traj.ctStart - for i in range(traj.np): - f.write(str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + '\n') - ct += ctStep - f.close() - #print(' Saving trajectory data to file ... ', end='') -#AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strTrjOutFileName)) +#partTraj.save_ascii(os.path.join(os.getcwd(), strExDataFolderName, strTrjOutFileName)) #print('done') print(' Saving intensity data to file ... ', end='') -AuxSaveS0Data(stkF, os.path.join(os.getcwd(), strExDataFolderName, strFluxOutFileName)) -AuxSaveS0Data(stkP, os.path.join(os.getcwd(), strExDataFolderName, strPowOutFileName)) +srwl_uti_save_intens_ascii(stkF.arS, stkF.mesh, os.path.join(os.getcwd(), strExDataFolderName, strFluxOutFileName), 0, ['Photon Energy', '', '', 'Flux'], _arUnits=['eV', '', '', 'ph/s/.1%bw']) +srwl_uti_save_intens_ascii(stkP.arS, stkP.mesh, os.path.join(os.getcwd(), strExDataFolderName, strPowOutFileName), 0, ['', 'Horizontal Position', 'Vertical Position', 'Power Density'], _arUnits=['', 'm', 'm', 'W/mm^2']) +print('done') + +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') + +uti_plot1d(stkF.arS, [stkF.mesh.eStart, stkF.mesh.eFin, stkF.mesh.ne], ['Photon Energy [eV]', 'Flux [ph/s/.1%bw]', 'Flux through Finite Aperture']) + +plotMeshX = [1000*stkP.mesh.xStart, 1000*stkP.mesh.xFin, stkP.mesh.nx] +plotMeshY = [1000*stkP.mesh.yStart, 1000*stkP.mesh.yFin, stkP.mesh.ny] +uti_plot2d(stkP.arS, plotMeshX, plotMeshY, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Power Density']) +#uti_plot1d(stkPx.arS, plotMeshX, ['Horizontal Position [mm]', 'Power Density [W/mm^2]', 'Power Density cut at y = 0']) +#uti_plot1d(stkPy.arS, plotMeshY, ['Vertical Position [mm]', 'Power Density [W/mm^2]', 'Power Density cut at x = 0']) + +powDenVsX = array('f', [0]*stkP.mesh.nx) +for i in range(stkP.mesh.nx): powDenVsX[i] = stkP.arS[stkP.mesh.nx*int(stkP.mesh.ny*0.5) + i] +uti_plot1d(powDenVsX, plotMeshX, ['Horizontal Position [mm]', 'Power Density [W/mm^2]', 'Power Density\n(horizontal cut at y = 0)']) + +powDenVsY = array('f', [0]*stkP.mesh.ny) +for i in range(stkP.mesh.ny): powDenVsY[i] = stkP.arS[int(stkP.mesh.nx*0.5) + i*stkP.mesh.ny] +uti_plot1d(powDenVsY, plotMeshY, ['Vertical Position [mm]', 'Power Density [W/mm^2]', 'Power Density\n(vertical cut at x = 0)']) + +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) print('done') diff --git a/env/release/srw_python/SRWLIB_Example06_PETRA.py b/env/release/srw_python/SRWLIB_Example06_PETRA.py new file mode 100644 index 00000000..b9406466 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example06_PETRA.py @@ -0,0 +1,232 @@ +############################################################################# +# SRWLIB Example#6: Calculating spectral flux of undulator radiation +# by finite-emittance electron beam collected through a finite aperture +# and power density distribution of this radiation (integrated over all photon energies) +# v 0.03 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +#from uti_plot import * #required for plotting +import os +import sys + +print('SRWLIB Extended Example # 6:') +print('Calculating spectral flux of undulator radiation by finite-emittance electron beam collected through a finite aperture and power density distribution of this radiation (integrated over all photon energies)') + +#**********************Input Parameters: +strExDataFolderName = 'data_example_06' #example data sub-folder name +strFluxOutFileName = 'ex06_res_flux.dat' #file name for output UR flux data +strTrjOutFileName = 'ex06_res_trj.dat' #file name for output trajectory data +strSingleElSpecOutFileName = 'ex06_res_single_e_spec.dat' #file name for output single-e spectrum data +strSingleElIntOutFileName = 'ex06_res_single_e_int.dat' #file name for output single-e intensity data +strPowOutFileName = 'ex06_res_pow.dat' #file name for output power density data +strPowTrjOutFileName = 'ex06_res_pow_trj.dat' #file name for output power density data +strSpecIntOutFileName = 'ex06_res_spec_int.dat' #file name for output UR spectral intensity data + +#***********Undulator +harmB = SRWLMagFldH() #magnetic field harmonic +harmB.n = 1 #harmonic number +harmB.h_or_v = 'v' #magnetic field plane: horzontal ('h') or vertical ('v') +harmB.B = 0.920902 #1. #magnetic field amplitude [T] +harmB.s = 1 #assuming symmetric magnetic field vs long. pos. +und = SRWLMagFldU([harmB]) +und.per = 0.0314 #0.02 #period length [m] +und.nPer = 63 #150 #number of periods (will be rounded to integer) +magFldCnt = SRWLMagFldC([und], array('d', [0]), array('d', [0]), array('d', [0])) #Container of all magnetic field elements + +#***********Electron Beam +eBeam = SRWLPartBeam() +eBeam.Iavg = 0.1 #0.5 #average current [A] +eBeam.partStatMom1.x = 0. #initial transverse positions [m] +eBeam.partStatMom1.y = 0. +eBeam.partStatMom1.z = 0. #initial longitudinal positions (set in the middle of undulator) +eBeam.partStatMom1.xp = 0 #initial relative transverse velocities +eBeam.partStatMom1.yp = 0 +eBeam.partStatMom1.gamma = 6.08/0.5109989e-03 #3./0.51099890221e-03 #relative energy +sigEperE = 0.0011 #0.00089 #relative RMS energy spread +sigX = 141.4e-06 #33.33e-06 #horizontal RMS size of e-beam [m] +sigXp = 7.071e-06 #16.5e-06 #horizontal RMS angular divergence [rad] +sigY = 4.879e-06 #2.912e-06 #vertical RMS size of e-beam [m] +sigYp = 2.05e-06 #2.7472e-06 #vertical RMS angular divergence [rad] +#2nd order stat. moments: +eBeam.arStatMom2[0] = sigX*sigX #<(x-)^2> +eBeam.arStatMom2[1] = 0 #<(x-)(x'-)> +eBeam.arStatMom2[2] = sigXp*sigXp #<(x'-)^2> +eBeam.arStatMom2[3] = sigY*sigY #<(y-)^2> +eBeam.arStatMom2[4] = 0 #<(y-)(y'-)> +eBeam.arStatMom2[5] = sigYp*sigYp #<(y'-)^2> +eBeam.arStatMom2[10] = sigEperE*sigEperE #<(E-)^2>/^2 + +#***********Auxiliary Electron Trajectory structure (for test) +partTraj = SRWLPrtTrj() #defining auxiliary trajectory structure +partTraj.partInitCond = eBeam.partStatMom1 +partTraj.allocate(20001) +partTraj.ctStart = -1.6 #Start "time" for the calculation +partTraj.ctEnd = 1.6 + +#***********Precision Parameters +arPrecF = [0]*5 #for spectral flux vs photon energy +arPrecF[0] = 1 #initial UR harmonic to take into account +arPrecF[1] = 21 #final UR harmonic to take into account +arPrecF[2] = 1. #longitudinal integration precision parameter +arPrecF[3] = 1. #azimuthal integration precision parameter +arPrecF[4] = 1 #calculate flux within aperture (1) or flux per unit surface (2) + +arPrecP = [0]*5 #for power density +arPrecP[0] = 1.5 #precision factor +arPrecP[1] = 1 #power density computation method (1- "near field", 2- "far field") +arPrecP[2] = 0 #initial longitudinal position (effective if arPrecP[2] < arPrecP[3]) +arPrecP[3] = 0 #final longitudinal position (effective if arPrecP[2] < arPrecP[3]) +arPrecP[4] = 20000 #number of points for (intermediate) trajectory calculation + +arPrecS = [0]*7 #for electric field and single-electron intensity +arPrecS[0] = 1 #SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" +arPrecS[1] = 0.01 #relative precision +arPrecS[2] = 0 #longitudinal position to start integration (effective if < zEndInteg) +arPrecS[3] = 0 #longitudinal position to finish integration (effective if > zStartInteg) +arPrecS[4] = 20000 #Number of points for intermediate trajectory calculation +arPrecS[5] = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) +arPrecS[6] = -1 #0.1 #sampling factor for adjusting nx, ny (effective if > 0) + +#***********Defining mesh and allocating memory for UR Stokes parameters and Power Density distributions +stkF = SRWLStokes() #for spectral flux vs photon energy +stkF.allocate(10000, 1, 1) #numbers of points vs photon energy, horizontal and vertical positions +stkF.mesh.zStart = 50. #30. #longitudinal position [m] at which UR has to be calculated +stkF.mesh.eStart = 10. #initial photon energy [eV] +stkF.mesh.eFin = 40.e+03 #20000. #final photon energy [eV] +stkF.mesh.xStart = -0.0015 #initial horizontal position of the collection aperture [m] +stkF.mesh.xFin = 0.0015 #final horizontal position of the collection aperture [m] +stkF.mesh.yStart = -0.001 #initial vertical position of the collection aperture [m] +stkF.mesh.yFin = 0.001 #final vertical position of the collection aperture [m] + +wfrS = SRWLWfr() #For on-axis single-electron intensity vs photon energy +wfrS.allocate(20000, 1, 1) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions +wfrS.mesh.zStart = stkF.mesh.zStart #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated +wfrS.mesh.eStart = stkF.mesh.eStart #Initial Photon Energy [eV] +wfrS.mesh.eFin = stkF.mesh.eFin #Final Photon Energy [eV] +wfrS.mesh.xStart = 0 #Initial Horizontal Position [m] +wfrS.mesh.xFin = 0 #Final Horizontal Position [m] +wfrS.mesh.yStart = 0 #Initial Vertical Position [m] +wfrS.mesh.yFin = 0 #Final Vertical Position [m] +wfrS.partBeam = eBeam + +wfrI = SRWLWfr() #For single-electron intensity at fixed photon energy +wfrI.allocate(1, 201, 201) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions +wfrI.mesh.zStart = stkF.mesh.zStart #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated +wfrI.mesh.eStart = 7.208e+03 #Initial Photon Energy [eV] +wfrI.mesh.eFin = wfrI.mesh.eStart #Final Photon Energy [eV] +wfrI.mesh.xStart = stkF.mesh.xStart #Initial Horizontal Position [m] +wfrI.mesh.xFin = stkF.mesh.xFin #Final Horizontal Position [m] +wfrI.mesh.yStart = stkF.mesh.yStart #Initial Vertical Position [m] +wfrI.mesh.yFin = stkF.mesh.yFin #Final Vertical Position [m] +wfrI.partBeam = eBeam + +stkP = SRWLStokes() #for power density +stkP.allocate(1, 101, 101) #numbers of points vs horizontal and vertical positions (photon energy is not taken into account) +stkP.mesh.zStart = 50. #30. #longitudinal position [m] at which power density has to be calculated +stkP.mesh.xStart = -0.02 #initial horizontal position [m] +stkP.mesh.xFin = 0.02 #final horizontal position [m] +stkP.mesh.yStart = -0.015 #initial vertical position [m] +stkP.mesh.yFin = 0.015 #final vertical position [m] + +stkFS = SRWLStokes() #for flux per unit surface vs photon energy, horizontal and vertical position +stkFS.allocate(9, 21, 21) #numbers of points vs photon energy, horizontal and vertical positions +stkFS.mesh.zStart = 50. #longitudinal position [m] at which UR has to be calculated +stkFS.mesh.eStart = 7.14e+03 #10. #initial photon energy [eV] +stkFS.mesh.eFin = 7.26e+03 #final photon energy [eV] +stkFS.mesh.xStart = -0.002 #initial horizontal position of the collection aperture [m] +stkFS.mesh.xFin = 0.002 #final horizontal position of the collection aperture [m] +stkFS.mesh.yStart = -0.0015 #initial vertical position of the collection aperture [m] +stkFS.mesh.yFin = 0.0015 #final vertical position of the collection aperture [m] + +#sys.exit(0) + +#**********************Calculation (SRWLIB function calls) + +print(' Performing Spectral Flux (Stokes parameters) vs Photon Energy calculation ... ', end='') +srwl.CalcStokesUR(stkF, eBeam, und, arPrecF) +print('done') + +print(' Performing Electron Trajectory calculation (for test) ... ', end='') +srwl.CalcPartTraj(partTraj, magFldCnt, [1]) +print('done') + +print(' Performing Single-E Electric Field calculation (vs photon energy) ... ', end='') +srwl.CalcElecFieldSR(wfrS, 0, magFldCnt, arPrecS) +print('done') +print(' Extracting Intensity from the Calculated Electric Field ... ', end='') +arIS = array('f', [0]*wfrS.mesh.ne) #array to take intensity data +srwl.CalcIntFromElecField(arIS, wfrS, 6, 0, 0, wfrS.mesh.eStart, 0, 0) +print('done') + +print(' Performing Single-E Electric Field calculation (vs hor. and vert. positions) ... ', end='') +srwl.CalcElecFieldSR(wfrI, 0, magFldCnt, arPrecS) +print('done') +print(' Extracting Intensity from the Calculated Electric Field ... ', end='') +arI = array('f', [0]*wfrI.mesh.nx*wfrI.mesh.ny) #array to take intensity data +srwl.CalcIntFromElecField(arI, wfrI, 6, 0, 3, wfrI.mesh.eStart, 0, 0) +print('done') + +print(' Performing Power Density calculation (from magnetic field) ... ', end='') +srwl.CalcPowDenSR(stkP, eBeam, 0, magFldCnt, arPrecP) +print('done') + +print(' Performing Power Density calculation (from trajectory) ... ', end='') +stkP1 = deepcopy(stkP) +srwl.CalcPowDenSR(stkP1, eBeam, partTraj, 0, arPrecP) +print('done') + +print(' Performing calculation of Spectral Intensity (Stokes parameters) vs photon energy, hor. and vert. positions (takes a bit of time) ... ', end='') +arPrecF[0] = 3 #initial UR harmonic to take into account +arPrecF[1] = 4 #final UR harmonic to take into account +arPrecF[2] = 1. #longitudinal integration precision parameter +arPrecF[3] = 1. #azimuthal integration precision parameter +arPrecF[4] = 2 #calculate flux within aperture (1) or flux per unit surface (2) +#srwl.CalcStokesUR(stkFS, eBeam, und, arPrecF) +print('done') + +#**********************Saving results +#Auxiliary function to write tabulated Trajectory data to ASCII file: +def AuxSaveTrajData(traj, filePath): + f = open(filePath, 'w') + resStr = '#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]' + if(hasattr(traj, 'arBx')): + resStr += ', Bx [T]' + if(hasattr(traj, 'arBy')): + resStr += ', By [T]' + if(hasattr(traj, 'arBz')): + resStr += ', Bz [T]' + f.write(resStr + '\n') + ctStep = 0 + if traj.np > 0: + ctStep = (traj.ctEnd - traj.ctStart)/(traj.np - 1) + ct = traj.ctStart + for i in range(traj.np): + resStr = str(ct) + '\t' + repr(traj.arX[i]) + '\t' + repr(traj.arXp[i]) + '\t' + repr(traj.arY[i]) + '\t' + repr(traj.arYp[i]) + '\t' + repr(traj.arZ[i]) + '\t' + repr(traj.arZp[i]) + if(hasattr(traj, 'arBx')): + resStr += '\t' + repr(traj.arBx[i]) + if(hasattr(traj, 'arBy')): + resStr += '\t' + repr(traj.arBy[i]) + if(hasattr(traj, 'arBz')): + resStr += '\t' + repr(traj.arBz[i]) + f.write(resStr + '\n') + ct += ctStep + f.close() + +print(' Saving spectral flux [ph/s/.1%bw], flux per unit surface [ph/s/.1%bw/mm^2], poower density [W/mm^2], and electron trajectory data to files ... ', end='') + +srwl_uti_save_intens_ascii(stkF.arS, stkF.mesh, os.path.join(os.getcwd(), strExDataFolderName, strFluxOutFileName), 0, ['Photon Energy', '', '', 'Flux'], _arUnits=['eV', '', '', 'ph/s/.1%bw']) + +AuxSaveTrajData(partTraj, os.path.join(os.getcwd(), strExDataFolderName, strTrjOutFileName)) +srwl_uti_save_intens_ascii(arIS, wfrS.mesh, os.path.join(os.getcwd(), strExDataFolderName, strSingleElSpecOutFileName)) + +srwl_uti_save_intens_ascii(arI, wfrI.mesh, os.path.join(os.getcwd(), strExDataFolderName, strSingleElIntOutFileName)) + +srwl_uti_save_intens_ascii(stkP.arS, stkP.mesh, os.path.join(os.getcwd(), strExDataFolderName, strPowOutFileName), 0, ['', 'Horizontal Position', 'Vertical Position', 'Power Density'], _arUnits=['', 'm', 'm', 'W/mm^2']) + +srwl_uti_save_intens_ascii(stkP1.arS, stkP1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strPowTrjOutFileName), 0, ['', 'Horizontal Position', 'Vertical Position', 'Power Density'], _arUnits=['', 'm', 'm', 'W/mm^2']) + +#AuxSaveS0Data(stkFS, os.path.join(os.getcwd(), strExDataFolderName, strSpecIntOutFileName)) + +print('done') diff --git a/env/release/srw_python/SRWLIB_Example07.py b/env/release/srw_python/SRWLIB_Example07.py index b3777b78..8775964e 100644 --- a/env/release/srw_python/SRWLIB_Example07.py +++ b/env/release/srw_python/SRWLIB_Example07.py @@ -1,65 +1,31 @@ -########################################################################### +############################################################################# # SRWLIB Example#7: Simulating propagation of a Gaussian X-ray beam through a simple optical scheme containing CRL -# v 0.03 +# v 0.07 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * #required for plotting import os -import sys -import math import random import copy print('SRWLIB Python Example # 7:') print('Simulating propagation of a Gaussian X-ray beam through a simple optical scheme containing CRL') -#**********************Auxiliary Functions - -#Write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() - -#Write Optical Transmission characteristic data to ASCII file: -def AuxSaveOpTransmData(optTr, t, filePath): - f = open(filePath, 'w') - f.write('#C-aligned optical Transmission characteristic (inner loop is vs horizontal position, outer loop vs vertical position)\n') - f.write('#' + repr(1) + ' #Reserved for Initial Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Final Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Number of points vs Photon Energy\n') - f.write('#' + repr(optTr.x - 0.5*optTr.rx) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(optTr.x + 0.5*optTr.rx) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(optTr.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(optTr.y - 0.5*optTr.ry) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(optTr.y + 0.5*optTr.ry) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(optTr.ny) + ' #Number of points vs Vertical Position\n') - for i in range(optTr.nx*optTr.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - tr = 0 - if((t == 1) or (t == 2)): #amplitude or intensity transmission - tr = optTr.arTr[i*2] - if(t == 2): #intensity transmission - tr *= tr - else: #optical path difference - tr = optTr.arTr[i*2 + 1] - f.write(' ' + repr(tr) + '\n') - f.close() - #**********************Input Parameters and structures: - + strDataFolderName = 'data_example_07' #data sub-folder name +strIntOutFileName1 = 'ex07_res_int_in.dat' #file name for output SR intensity data +strPhOutFileName1 = 'ex07_res_ph_in.dat' #file name for output SR phase data +strIntPropOutFileName1 = 'ex07_res_int_dist_crl_p1.dat' #file name for output SR intensity data +strPhPropOutFileName1 = 'ex07_res_ph_dist_crl_p1.dat' #file name for output SR phase data +strIntPropOutFileName2 = 'ex07_res_int_dist_crl_p2.dat' #file name for output SR intensity data +strPhPropOutFileName2 = 'ex07_res_ph_dist_crl_p2.dat' #file name for output SR phase data +strIntPropOutFileName3 = 'ex07_res_int_perf_crl_p2.dat' #file name for output SR intensity data +strPhPropOutFileName3 = 'ex07_res_ph_perf_crl_p2.dat' #file name for output SR phase data +strOpPathOutFileName1 = 'ex07_res_opt_path_dif_dist_crl.dat' #file name for output SR intensity data +strOpPathOutFileName2 = 'ex07_res_opt_path_dif_perf_crl.dat' #file name for output SR intensity data GsnBm = SRWLGsnBm() #Gaussian Beam structure (just parameters) GsnBm.x = 0 #Transverse Coordinates of Gaussian Beam Center at Waist [m] @@ -73,7 +39,7 @@ def AuxSaveOpTransmData(optTr, t, filePath): GsnBm.polar = 1 #1- linear hoirizontal GsnBm.sigX = 23e-06/2.35 #Horiz. RMS size at Waist [m] GsnBm.sigY = GsnBm.sigX #Vert. RMS size at Waist [m] -GsnBm.sigT = 10e-15 #Pulse duration [fs] (not used?) +GsnBm.sigT = 10e-15 #Pulse duration [s] (not used?) GsnBm.mx = 0 #Transverse Gauss-Hermite Mode Orders GsnBm.my = 0 @@ -100,13 +66,18 @@ def AuxSaveOpTransmData(optTr, t, filePath): #**********************Calculating Initial Wavefront and extracting Intensity: srwl.CalcElecFieldGaussian(wfr, GsnBm, arPrecPar) -arI = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data -srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) #extracts intensity -AuxSaveIntData(arI, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_in.dat")) +arI0 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data +srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) #extracts intensity +srwl_uti_save_intens_ascii(arI0, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileName1), 0) + +arI0x = array('f', [0]*wfr.mesh.nx) #array to take 1D intensity data +srwl.CalcIntFromElecField(arI0x, wfr, 6, 0, 1, wfr.mesh.eStart, 0, 0) #extracts intensity -arP = array('d', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') -srwl.CalcIntFromElecField(arP, wfr, 0, 4, 3, wfr.mesh.eStart, 0, 0) #extracts radiation phase -AuxSaveIntData(arP, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_in.dat")) +arP0 = array('d', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') +srwl.CalcIntFromElecField(arP0, wfr, 0, 4, 3, wfr.mesh.eStart, 0, 0) #extracts radiation phase +srwl_uti_save_intens_ascii(arP0, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, strPhOutFileName1), 0, ['', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['', 'm', 'm', 'rad']) + +mesh0 = deepcopy(wfr.mesh) #***********Optical Elements @@ -118,21 +89,30 @@ def AuxSaveOpTransmData(optTr, t, filePath): wallThickCRL = 50e-06 #CRL wall thickness [m] opCRLperf = 1 #set to 1 if simulation of perfect CRL is required, otherwise set to None -opCRLdist = None #set to 1 if simulation of distorted CRL is required, otherwise set to None +opCRLdist = 1 #None #set to 1 if simulation of distorted CRL is required, otherwise set to None + +opPathDifCRL = None +opPathDifCRLx = None +opPathDifCRLy = None +opMeshCRL = None #Generating a perfect 2D parabolic CRL: if(opCRLperf != None): print('Setting-up Perfect CRL...') opCRLperf = srwl_opt_setup_CRL(3, delta, attenLen, 1, diamCRL, diamCRL, rMinCRL, nCRL, wallThickCRL, 0, 0) print('done') - #Saving transmission data to file - AuxSaveOpTransmData(opCRLperf, 3, os.path.join(os.getcwd(), strDataFolderName, "res_opt_path_dif_perf_crl.dat")) + #Extracting transmission data characteristic for subsequent plotting and saving it to a file + opPathDifCRL = opCRLperf.get_data(3, 3) + srwl_uti_save_intens_ascii(opPathDifCRL, opCRLperf.mesh, os.path.join(os.getcwd(), strDataFolderName, strOpPathOutFileName2), 0, ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) + opPathDifCRLx = opCRLperf.get_data(3, 1, _y=0) + opPathDifCRLy = opCRLperf.get_data(3, 2, _x=0) + opMeshCRL = opCRLperf.mesh if(opCRLdist != None): print('Setting-up CRL Distorted by \"voids\" in volume (takes time)...') #Generating array of Void Centers and Radii, and a CRL with these (spherical) Voids: - nVoidInRectPar = 1000 #parameter controlling density of voids - baseNx = 201 #(auxiliary) numbers of points in tabulated functions to be used (in rejectrion method) + nVoidInRectPar = 100 #1000 #parameter controlling density of voids + baseNx = 201 #(auxiliary) numbers of points in tabulated functions to be used (in the rejection method) baseNy = 201 rMinVoid = 2e-06 #min. void radius rMaxVoid = 25e-06 #max. void radius @@ -171,7 +151,12 @@ def AuxSaveOpTransmData(optTr, t, filePath): #Generating distorted CRL, with voids opCRLdist = srwl_opt_setup_CRL(3, delta, attenLen, 1, diamCRL, diamCRL, rMinCRL, nCRL, wallThickCRL, 0, 0, arVoidCenCoordInCRL) print('done') - AuxSaveOpTransmData(opCRLdist, 3, os.path.join(os.getcwd(), strDataFolderName, "res_opt_path_dif_dist_crl.dat")) + #Extracting transmission data characteristic for subsequent plotting and saving it to a file + opPathDifCRL = opCRLdist.get_data(3, 3) + srwl_uti_save_intens_ascii(opPathDifCRL, opCRLdist.mesh, os.path.join(os.getcwd(), strDataFolderName, strOpPathOutFileName1), 0, ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) + opPathDifCRLx = opCRLdist.get_data(3, 1, _y=0) + opPathDifCRLy = opCRLdist.get_data(3, 2, _x=0) + opMeshCRL = opCRLdist.mesh opApCRL = SRWLOptA('r', 'a', diamCRL, diamCRL) #Aperture at CRL @@ -192,7 +177,9 @@ def AuxSaveOpTransmData(optTr, t, filePath): #[9]: Type of wavefront Shift before Resizing (not yet implemented) #[10]: New Horizontal wavefront Center position after Shift (not yet implemented) #[11]: New Vertical wavefront Center position after Shift (not yet implemented) -prParRes1 = [0, 0, 1., 1, 0, 1.1, 8., 1.1, 8., 0, 0, 0] +#prParRes1 = [0, 0, 1., 1, 0, 1.1, 8., 1.1, 8., 0, 0, 0] +prParRes1 = [0, 0, 1., 1, 0, 1.1, 10., 1.1, 10., 0, 0, 0] + prParRes0 = [0, 0, 1., 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] #"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) @@ -205,6 +192,16 @@ def AuxSaveOpTransmData(optTr, t, filePath): #sys.exit(0) #***********Wavefront Propagation +arI1 = None; arI1x = None; arI1y = None +arP1 = None +mesh1 = None +arI2 = None; arI2x = None; arI2y = None +arP2 = None +mesh2 = None +arI3 = None; arI3x = None; arI3y = None +arP3 = None +mesh3 = None + if(opCRLdist != None): #Duplicating wavefront (by re-creating all objects/arrays): wfr1 = copy.deepcopy(wfr) @@ -214,12 +211,18 @@ def AuxSaveOpTransmData(optTr, t, filePath): srwl.PropagElecField(wfr1, optBLdistCDI) print('done') print('Saving resulting Intensity and Phase data to files...', end='') - arI = array('f', [0]*wfr1.mesh.nx*wfr1.mesh.ny) #"flat" array to take 2D intensity data - srwl.CalcIntFromElecField(arI, wfr1, 6, 0, 3, wfr1.mesh.eStart, 0, 0) #extracts intensity - AuxSaveIntData(arI, wfr1.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_dist_crl_short_drift.dat")) - arP = array('d', [0]*wfr1.mesh.nx*wfr1.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') - srwl.CalcIntFromElecField(arP, wfr1, 0, 4, 3, wfr1.mesh.eStart, 0, 0) #extracts radiation phase - AuxSaveIntData(arP, wfr1.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_dist_crl_short_drift.dat")) + mesh1 = deepcopy(wfr1.mesh) + arI1 = array('f', [0]*mesh1.nx*mesh1.ny) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arI1, wfr1, 6, 0, 3, mesh1.eStart, 0, 0) #extracts intensity + srwl_uti_save_intens_ascii(arI1, mesh1, os.path.join(os.getcwd(), strDataFolderName, strIntPropOutFileName1), 0) + + arI1x = array('f', [0]*mesh1.nx) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI1x, wfr1, 6, 0, 1, mesh1.eStart, 0, 0) #extracts intensity + arI1y = array('f', [0]*mesh1.ny) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI1y, wfr1, 6, 0, 2, mesh1.eStart, 0, 0) #extracts intensity + arP1 = array('d', [0]*mesh1.nx*mesh1.ny) #"flat" array to take 2D phase data (note it should be 'd') + srwl.CalcIntFromElecField(arP1, wfr1, 0, 4, 3, mesh1.eStart, 0, 0) #extracts radiation phase + srwl_uti_save_intens_ascii(arP1, mesh1, os.path.join(os.getcwd(), strDataFolderName, strPhPropOutFileName1), 0, ['', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['', 'm', 'm', 'rad']) del wfr1 print('done') @@ -227,12 +230,18 @@ def AuxSaveOpTransmData(optTr, t, filePath): srwl.PropagElecField(wfr2, optBLdist) print('done') print('Saving resulting Intensity and Phase data to files...', end='') - arI = array('f', [0]*wfr2.mesh.nx*wfr2.mesh.ny) #"flat" array to take 2D intensity data - srwl.CalcIntFromElecField(arI, wfr2, 6, 0, 3, wfr2.mesh.eStart, 0, 0) #extracts intensity - AuxSaveIntData(arI, wfr2.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_dist_crl_waist.dat")) - arP = array('d', [0]*wfr2.mesh.nx*wfr2.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') - srwl.CalcIntFromElecField(arP, wfr2, 0, 4, 3, wfr2.mesh.eStart, 0, 0) #extracts radiation phase - AuxSaveIntData(arP, wfr2.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_dist_crl_waist.dat")) + mesh2 = deepcopy(wfr2.mesh) + arI2 = array('f', [0]*mesh2.nx*mesh2.ny) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arI2, wfr2, 6, 0, 3, mesh2.eStart, 0, 0) #extracts intensity + srwl_uti_save_intens_ascii(arI2, mesh2, os.path.join(os.getcwd(), strDataFolderName, strIntPropOutFileName2), 0) + + arI2x = array('f', [0]*mesh2.nx) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI2x, wfr2, 6, 0, 1, mesh2.eStart, 0, 0) #extracts intensity + arI2y = array('f', [0]*mesh2.ny) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI2y, wfr2, 6, 0, 2, mesh2.eStart, 0, 0) #extracts intensity + arP2 = array('d', [0]*mesh2.nx*mesh2.ny) #"flat" array to take 2D phase data (note it should be 'd') + srwl.CalcIntFromElecField(arP2, wfr2, 0, 4, 3, mesh2.eStart, 0, 0) #extracts radiation phase + srwl_uti_save_intens_ascii(arP2, mesh2, os.path.join(os.getcwd(), strDataFolderName, strPhPropOutFileName2), 0, ['', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['', 'm', 'm', 'rad']) del wfr2 print('done') @@ -241,10 +250,73 @@ def AuxSaveOpTransmData(optTr, t, filePath): srwl.PropagElecField(wfr, optBLperf) print('done') print('Saving resulting data to files...', end='') - arI = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data - srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) #extracts intensity - AuxSaveIntData(arI, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_perf_crl_waist.dat")) - arP = array('d', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') - srwl.CalcIntFromElecField(arP, wfr, 0, 4, 3, wfr.mesh.eStart, 0, 0) #extracts radiation phase - AuxSaveIntData(arP, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_perf_crl_waist.dat")) + mesh3 = deepcopy(wfr.mesh) + arI3 = array('f', [0]*mesh3.nx*mesh3.ny) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arI3, wfr, 6, 0, 3, mesh3.eStart, 0, 0) #extracts intensity + srwl_uti_save_intens_ascii(arI3, mesh3, os.path.join(os.getcwd(), strDataFolderName, strIntPropOutFileName3), 0) + + arI3x = array('f', [0]*mesh3.nx) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI3x, wfr, 6, 0, 1, mesh3.eStart, 0, 0) #extracts intensity + arI3y = array('f', [0]*mesh3.ny) #array to take 1D intensity data + srwl.CalcIntFromElecField(arI3y, wfr, 6, 0, 2, mesh3.eStart, 0, 0) #extracts intensity + arP3 = array('d', [0]*mesh3.nx*mesh3.ny) #"flat" array to take 2D phase data (note it should be 'd') + srwl.CalcIntFromElecField(arP3, wfr, 0, 4, 3, mesh3.eStart, 0, 0) #extracts radiation phase + srwl_uti_save_intens_ascii(arP3, mesh3, os.path.join(os.getcwd(), strDataFolderName, strPhPropOutFileName3), 0, ['', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['', 'm', 'm', 'rad']) print('done') + +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +plotMesh0x = [1000*mesh0.xStart, 1000*mesh0.xFin, mesh0.nx] +plotMesh0y = [1000*mesh0.yStart, 1000*mesh0.yFin, mesh0.ny] +uti_plot2d(arI0, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity Before Propagation']) +uti_plot1d(arI0x, plotMesh0x, ['Horizontal Position [mm]', 'Intensity [a.u.]', 'Intensity Before Propagation\n(cut vs horizontal position at y = 0)']) +uti_plot2d(arP0, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Phase Before Propagation']) + +if opMeshCRL != None: + plotMeshCRLx = [1000*opMeshCRL.xStart, 1000*opMeshCRL.xFin, opMeshCRL.nx] + plotMeshCRLy = [1000*opMeshCRL.yStart, 1000*opMeshCRL.yFin, opMeshCRL.ny] + if opPathDifCRL != None: + uti_plot2d(opPathDifCRL, plotMeshCRLx, plotMeshCRLy, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'CRL Optical Path Difference']) + if opPathDifCRLx != None: + uti_plot1d(opPathDifCRLx, plotMeshCRLx, ['Horizontal Position [mm]', 'Optical Path Diff. [m]', 'CRL Optical Path Difference\n(cut vs horizontal position at y = 0)']) + if opPathDifCRLy != None: + uti_plot1d(opPathDifCRLy, plotMeshCRLy, ['Vertical Position [mm]', 'Optical Path Diff. [m]', 'CRL Optical Path Difference\n(cut vs vertical position at x = 0)']) + +if mesh1 != None: + plotMesh1x = [1e+06*mesh1.xStart, 1e+06*mesh1.xFin, mesh1.nx] + plotMesh1y = [1e+06*mesh1.yStart, 1e+06*mesh1.yFin, mesh1.ny] + if arI1 != None: + uti_plot2d(arI1, plotMesh1x, plotMesh1y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Intensity After Propagation']) + if arI1x != None: + uti_plot1d(arI1x, plotMesh1x, ['Horizontal Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation\n(horizontal cut at y = 0)']) + if arI1y != None: + uti_plot1d(arI1y, plotMesh1y, ['Vertical Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation\n(vertical cut at x = 0)']) + if arP1 != None: + uti_plot2d(arP1, plotMesh1x, plotMesh1y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Phase After Propagation']) + +if mesh2 != None: + plotMesh2x = [1e+06*mesh2.xStart, 1e+06*mesh2.xFin, mesh2.nx] + plotMesh2y = [1e+06*mesh2.yStart, 1e+06*mesh2.yFin, mesh2.ny] + if arI2 != None: + uti_plot2d(arI2, plotMesh2x, plotMesh2y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Intensity After Propagation to Waist']) + if arI2x != None: + uti_plot1d(arI2x, plotMesh2x, ['Horizontal Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation to Waist\n(horizontal cut at y = 0)']) + if arI2y != None: + uti_plot1d(arI2y, plotMesh2y, ['Vertical Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation to Waist\n(vertical cut at x = 0)']) + if arP2 != None: + uti_plot2d(arP2, plotMesh2x, plotMesh2y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Phase After Propagation to Waist']) + +if mesh3 != None: + plotMesh3x = [1e+06*mesh3.xStart, 1e+06*mesh3.xFin, mesh3.nx] + plotMesh3y = [1e+06*mesh3.yStart, 1e+06*mesh3.yFin, mesh3.ny] + if arI3 != None: + uti_plot2d(arI3, plotMesh3x, plotMesh3y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Intensity After Propagation to Waist']) + if arI3x != None: + uti_plot1d(arI3x, plotMesh3x, ['Horizontal Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation to Waist\n(horizontal cut at y = 0)']) + if arI3y != None: + uti_plot1d(arI3y, plotMesh3y, ['Vertical Position [microns]', 'Intensity [a.u.]', 'Intensity After Propagation to Waist\n(vertical cut at x = 0)']) + if arP3 != None: + uti_plot2d(arP3, plotMesh3x, plotMesh3y, ['Horizontal Position [microns]', 'Vertical Position [microns]', 'Phase After Propagation to Waist']) + +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) +print('done') diff --git a/env/release/srw_python/SRWLIB_Example08.py b/env/release/srw_python/SRWLIB_Example08.py index 4b8998b9..eda5957a 100644 --- a/env/release/srw_python/SRWLIB_Example08.py +++ b/env/release/srw_python/SRWLIB_Example08.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- ############################################################################# -# SRWLIB Example#8: Simulating partially-coherent UR focusing with CRL -# v 0.02 +# SRWLIB Example#8: Simulating partially-coherent UR focusing with a CRL +# v 0.07 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * import os -import sys print('SRWLIB Python Example # 8:') print('Simulating emission and propagation of undulator radiation (UR) wavefront through a simple optical scheme including CRL') @@ -16,60 +15,21 @@ print('After this, calculation of partially-coherent UR from entire electron beam is started as a loop over "macro-electrons", using "srwl_wfr_emit_prop_multi_e" function. ', end='') print('This function can run either in "normal" sequential mode, or in parallel mode under "mpi4py".', end='') print('For this, an MPI2 package and the "mpi4py" Python package have to be installed and configured, and this example has to be started e.g. as:') -print(' mpiexec -n 5 python3 SRWLIB_Example08.py') +print(' mpiexec -n 5 python SRWLIB_Example08.py') print('For more information on parallel calculations under "mpi4py" please see documentation to the "mpi4py" and MPI.') print('Note that the long-lasting partially-coherent UR calculation saves from time to time instant average intensity to an ASCII file, ', end='') print('so the execution of the long loop over "macro-electrons" can be aborted after some time without the danger that all results will be lost.') print('') -#**********************Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() - -#**********************Auxiliary function to write Optical Transmission characteristic data to ASCII file: -def AuxSaveOpTransmData(optTr, t, filePath): - f = open(filePath, 'w') - f.write('#C-aligned optical Transmission characteristic (inner loop is vs horizontal position, outer loop vs vertical position)\n') - f.write('#' + repr(1) + ' #Reserved for Initial Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Final Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Number of points vs Photon Energy\n') - f.write('#' + repr(optTr.x - 0.5*optTr.rx) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(optTr.x + 0.5*optTr.rx) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(optTr.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(optTr.y - 0.5*optTr.ry) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(optTr.y + 0.5*optTr.ry) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(optTr.ny) + ' #Number of points vs Vertical Position\n') - for i in range(optTr.nx*optTr.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - tr = 0 - if((t == 1) or (t == 2)): #amplitude or intensity transmission - tr = optTr.arTr[i*2] - if(t == 2): #intensity transmission - tr *= tr - else: #optical path difference - tr = optTr.arTr[i*2 + 1] - f.write(' ' + repr(tr) + '\n') - f.close() - -#**********************Input Parameters: +#****************************Input Parameters: strExDataFolderName = 'data_example_08' #example data sub-folder name -strTrajOutFileName = 'wfr_res_traj.dat' #file name for output trajectory data -strIntOutFileName1 = 'wfr_res_crl_int1.dat' #file name for output SR intensity data -strIntOutFileName2 = 'wfr_res_crl_int2.dat' #file name for output SR intensity data -strIntOutFileName3 = 'wfr_res_crl_int3.dat' #file name for output SR intensity data -strIntOutFileNamePartCoh = 'wfr_res_crl_int_part_coh1.dat' #file name for output SR intensity data +strTrajOutFileName = 'ex08_res_traj.dat' #file name for output trajectory data +strIntOutFileName1 = 'ex08_res_int1.dat' #file name for output SR intensity data +strIntOutFileName2 = 'ex08_res_int2.dat' #file name for output SR intensity data +strIntOutFileName3 = 'ex08_res_int3.dat' #file name for output SR intensity data +strIntOutFileNamePartCoh = 'ex08_res_int_part_coh1.dat' #file name for output SR intensity data +strOpTrFileName = 'ex08_res_op_tr_crl.dat' #file name for output optical transmission data +strOpPathDifFileName = 'ex08_res_op_path_dif_crl.dat' #file name for optical path difference data #***********Undulator numPer = 72.5 #Number of ID Periods (without counting for terminations @@ -110,11 +70,12 @@ def AuxSaveOpTransmData(optTr, t, filePath): relPrec = 0.01 #relative precision zStartInteg = 0 #longitudinal position to start integration (effective if < zEndInteg) zEndInteg = 0 #longitudinal position to finish integration (effective if > zStartInteg) -npTraj = 20000 +npTraj = 20000 #Number of points for trajectory calculation +useTermin = 0 #1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) sampFactNxNyForProp = 0.25 #sampling factor for adjusting nx, ny (effective if > 0) -arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, 0, 0] +arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, 0] -#*********** Spectrum +#***********Spectrum data placeholder wfr1 = SRWLWfr() #For spectrum vs photon energy wfr1.allocate(10000, 1, 1) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions wfr1.mesh.zStart = 36.25 + 1.25 #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated @@ -126,7 +87,7 @@ def AuxSaveOpTransmData(optTr, t, filePath): wfr1.mesh.yFin = 0 #Final Vertical Position [m] wfr1.partBeam = elecBeam -#****************** Initial Wavefront +#***********Initial Wavefront data placeholder wfr2 = SRWLWfr() #For intensity distribution at fixed photon energy wfr2.allocate(1, 101, 101) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions wfr2.mesh.zStart = 36.25 + 1.25 #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated @@ -140,9 +101,9 @@ def AuxSaveOpTransmData(optTr, t, filePath): wfr2.partBeam = elecBeam -#***************** Optical Elements and Propagation Parameters -fx = 1e+23 #Focal length in Horizontal plane -fy = 19.0939 #Focal length in Horizontal plane +#***********Optical Elements and Propagation Parameters +fx = 1e+23 #Focal Length in Horizontal plane +fy = 19.0939 #Focal Length in Vertical plane optLens = SRWLOptL(fx, fy) #Ideal Lens delta = 4.3712962E-06 #Refractive index decrement of Be at 8830 eV @@ -154,18 +115,22 @@ def AuxSaveOpTransmData(optTr, t, filePath): wallThick = 50E-06 #[m] wall thickness of CRL optCRL = srwl_opt_setup_CRL(2, delta, attenLen, 1, geomApertNF, geomApertF, rMin, nCRL, wallThick, 0, 0) #1D CRL -#print(' Saving CRL transmission data to files (for viewing/debugging)...', end='') -#AuxSaveOpTransmData(optCRL, 2, os.path.join(os.getcwd(), strExDataFolderName, 'wfr_res_op_transm_CRL.dat')) -#AuxSaveOpTransmData(optCRL, 3, os.path.join(os.getcwd(), strExDataFolderName, 'wfr_res_op_path_dif_CRL.dat')) -#print('done') +print('Saving CRL transmission data to files (for viewing/debugging)...', end='') +optTrIntCRL = optCRL.get_data(2, 3) +srwl_uti_save_intens_ascii(optTrIntCRL, optCRL.mesh, os.path.join(os.getcwd(), strExDataFolderName, strOpTrFileName), 0, ['', 'Horizontal Position', 'Vertical Position', 'Intensity Transmission'], _arUnits=['', 'm', 'm', 'r.u.']) + +optPathDifCRL = optCRL.get_data(3, 3) +srwl_uti_save_intens_ascii(optPathDifCRL, optCRL.mesh, os.path.join(os.getcwd(), strExDataFolderName, strOpPathDifFileName), 0, ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) +print('done') optApert = SRWLOptA('r', 'a', geomApertNF, geomApertF) #Aperture optDrift = SRWLOptD(38.73) #Drift space -propagParApert = [0, 0, 1., 0, 0, 1.5, 1., 1.1, 8., 0, 0, 0] -propagParLens = [0, 0, 1., 0, 0, 1., 1., 1., 1., 0, 0, 0] -propagParDrift = [0, 0, 1., 1, 0, 1., 1.2, 1., 1., 0, 0, 0] +#propagParApert = [0, 0, 1., 0, 0, 1.5, 1.0, 1.1, 8., 0, 0, 0] +propagParApert = [0, 0, 1., 0, 0, 1.5, 1.0, 1.1, 6., 0, 0, 0] +propagParLens = [0, 0, 1., 0, 0, 1.0, 1.0, 1.0, 1., 0, 0, 0] +propagParDrift = [0, 0, 1., 1, 0, 1.0, 1.2, 1.0, 1., 0, 0, 0] #Wavefront Propagation Parameters: #[0]: Auto-Resize (1) or not (0) Before propagation @@ -183,46 +148,51 @@ def AuxSaveOpTransmData(optTr, t, filePath): optBL = SRWLOptC([optApert, optCRL, optDrift], [propagParApert, propagParLens, propagParDrift]) #"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) #optBL = SRWLOptC([optApert, optLens, optDrift], [propagParApert, propagParLens, propagParDrift]) #"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) -#**********************Calculation (SRWLIB function calls) +#****************************Calculation (SRWLIB function calls) if(srwl_uti_proc_is_master()): - print(' Performing Electric Field Wavefront calculation ... ', end='') + print('Performing Electric Field Wavefront calculation ... ', end='') srwl.CalcElecFieldSR(wfr1, 0, magFldCnt, arPrecPar) print('done') - print(' Extracting Intensity from the Calculated Electric Field ... ', end='') + print('Extracting Intensity from the Calculated Electric Field ... ', end='') arI1 = array('f', [0]*wfr1.mesh.ne) srwl.CalcIntFromElecField(arI1, wfr1, 6, 0, 0, wfr1.mesh.eStart, wfr1.mesh.xStart, wfr1.mesh.yStart) print('done') - print(' Saving the radiation spectrum data to a file ... ', end='') - AuxSaveIntData(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) + print('Saving the radiation spectrum data to a file ... ', end='') + #AuxSaveIntData(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) + srwl_uti_save_intens_ascii(arI1, wfr1.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1), 0) print('done') - print(' Performing Initial Electric Field calculation ... ', end='') + print('Performing Initial Electric Field calculation ... ', end='') arPrecPar[6] = sampFactNxNyForProp #sampling factor for adjusting nx, ny (effective if > 0) srwl.CalcElecFieldSR(wfr2, 0, magFldCnt, arPrecPar) print('done') - print(' Extracting Intensity from the Calculated Initial Electric Field ... ', end='') + print('Extracting Intensity from the Calculated Initial Electric Field ... ', end='') arI2 = array('f', [0]*wfr2.mesh.nx*wfr2.mesh.ny) #"flat" array to take 2D intensity data srwl.CalcIntFromElecField(arI2, wfr2, 6, 0, 3, wfr2.mesh.eStart, 0, 0) print('done') - print(' Saving the Initial Electric Field into a file ... ', end='') - AuxSaveIntData(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) + print('Saving the Initial Electric Field into a file ... ', end='') + #AuxSaveIntData(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) + srwl_uti_save_intens_ascii(arI2, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2), 0) print('done') - print(' Simulating Electric Field Wavefront Propagation ... ', end='') + print('Simulating Electric Field Wavefront Propagation ... ', end='') srwl.PropagElecField(wfr2, optBL) print('done') - print(' Extracting Intensity from the Propagated Electric Field ... ', end='') + print('Extracting Intensity from the Propagated Electric Field ... ', end='') arI3 = array('f', [0]*wfr2.mesh.nx*wfr2.mesh.ny) #"flat" 2D array to take intensity data srwl.CalcIntFromElecField(arI3, wfr2, 6, 0, 3, wfr2.mesh.eStart, 0, 0) print('done') - print(' Saving the Propagated Wavefront Intensity data to a file ... ', end='') - AuxSaveIntData(arI3, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName3)) + print('Saving the Propagated Wavefront Intensity data to a file ... ', end='') + #AuxSaveIntData(arI3, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName3)) + srwl_uti_save_intens_ascii(arI3, wfr2.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName3), 0) print('done') -#sys.exit(0) - -print(' Simulating Partially-Coherent Wavefront Propagation by summing-up contributions of SR from individual electrons (takes time)... ') -nMacroElec = 50000 -radStokesProp = srwl_wfr_emit_prop_multi_e(elecBeam, magFldCnt, meshInitPartCoh, 1, 0.01, nMacroElec, 5, 10, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileNamePartCoh), sampFactNxNyForProp, optBL) +print('Simulating Partially-Coherent Wavefront Propagation by summing-up contributions of SR from individual electrons (takes time)... ') +nMacroElec = 50000 #total number of macro-electrons +nMacroElecAvgPerProc = 5 #number of macro-electrons / wavefront to average on worker processes before sending data to master (for parallel calculation only) +nMacroElecSavePer = 10 #intermediate data saving periodicity (in macro-electrons) +srCalcMeth = 1 #SR calculation method +srCalcPrec = 0.01 #SR calculation rel. accuracy +radStokesProp = srwl_wfr_emit_prop_multi_e(elecBeam, magFldCnt, meshInitPartCoh, srCalcMeth, srCalcPrec, nMacroElec, nMacroElecAvgPerProc, nMacroElecSavePer, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileNamePartCoh), sampFactNxNyForProp, optBL) print('done') diff --git a/env/release/srw_python/SRWLIB_Example09.py b/env/release/srw_python/SRWLIB_Example09.py index 7400d988..0078246a 100644 --- a/env/release/srw_python/SRWLIB_Example09.py +++ b/env/release/srw_python/SRWLIB_Example09.py @@ -1,157 +1,73 @@ -########################################################################### -# SRWLIB Example#9: Simulating propagation of a Gaussian X-ray beam through a Beamline containing an Imperfect Mirror -# v 0.02 (based on input of L. Samoylova) +############################################################################# +# SRWLIB Example#9: Simulating propagation of a Gaussian X-ray beam through a Beamline containing Imperfect Mirrors +# v 0.03 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * +from uti_plot import * #required for plotting import os import sys -import math +import time print('SRWLIB Python Example # 9:') -print('Simulating propagation of a Coherent Gaussian X-ray beam through a Beamline containing an Imperfect Mirror') - -#**********************Auxiliary Functions - -#Read data comumns from ASCII file: -def AuxReadInDataColumns(filePath, nCol, strSep): - f = open(filePath, 'r') - resCols = [] - for iCol in range(nCol): - resCols.append([]) - - curLine = f.readline() - while len(curLine) > 0: - curLineParts = curLine.split(strSep) - for iCol in range(nCol): - if(iCol < len(curLineParts)): - resCols[iCol].append(float(curLineParts[iCol])) - curLine = f.readline() - f.close() - return resCols #attn: returns lists, not arrays! - -#Write tabulated resulting Intensity data to ASCII file: -def AuxSaveIntData(arI, mesh, filePath): - f = open(filePath, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(mesh.ny) + ' #Number of points vs Vertical Position\n') - for i in range(mesh.ne*mesh.nx*mesh.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - f.write(' ' + repr(arI[i]) + '\n') - f.close() - -#Write Optical Transmission characteristic data to ASCII file: -def AuxSaveOpTransmData(optTr, t, filePath): - f = open(filePath, 'w') - f.write('#C-aligned optical Transmission characteristic (inner loop is vs horizontal position, outer loop vs vertical position)\n') - f.write('#' + repr(1) + ' #Reserved for Initial Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Final Photon Energy [eV]\n') - f.write('#' + repr(1) + ' #Reserved for Number of points vs Photon Energy\n') - f.write('#' + repr(optTr.x - 0.5*optTr.rx) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(optTr.x + 0.5*optTr.rx) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(optTr.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(optTr.y - 0.5*optTr.ry) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(optTr.y + 0.5*optTr.ry) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(optTr.ny) + ' #Number of points vs Vertical Position\n') - for i in range(optTr.nx*optTr.ny): #write all data into one column using "C-alignment" as a "flat" 1D array - tr = 0 - if((t == 1) or (t == 2)): #amplitude or intensity transmission - tr = optTr.arTr[i*2] - if(t == 2): #intensity transmission - tr *= tr - else: #optical path difference - tr = optTr.arTr[i*2 + 1] - f.write(' ' + repr(tr) + '\n') - f.close() - -#Setup Transmission optical element with 1D heght profile data -def AuxTransmAddSurfHeightProfile(optSlopeErr, heightProfData, dim, ang): - argHeightProfData = heightProfData[0] - valHeightProfData = heightProfData[1] - sinAng = math.sin(ang) - npData = len(heightProfData[0]) - xStep = optSlopeErr.rx/(optSlopeErr.nx - 1) - yStep = optSlopeErr.ry/(optSlopeErr.ny - 1) - y = optSlopeErr.y - 0.5*optSlopeErr.ry - hApprox = 0 - ipStart = 0 - for iy in range(optSlopeErr.ny): - if('y' in dim): - hApprox = 0 - y1 = argHeightProfData[ipStart]*sinAng - for i in range(ipStart + 1, npData): - y2 = argHeightProfData[i]*sinAng - if((y1 <= y) and (y < y2)): - hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAng))*(y - y1) + valHeightProfData[i-1] - #print(ipStart, i, iy, y1, y, y2, argHeightProfData[i-1], argHeightProfData[i], valHeightProfData[i-1], valHeightProfData[i], hApprox) - ipStart = i - 1 - break - y1 = y2 - - x = optSlopeErr.x - 0.5*optSlopeErr.rx - - for ix in range(optSlopeErr.nx): - if('x' in dim): - if(ix == 0): ipStart = 0 - hApprox = 0 - x1 = argHeightProfData[ipStart]*sinAng - for i in range(ipStart + 1, npData): - x2 = argHeightProfData[i]*sinAng - if((x1 <= x) and (x < x2)): - hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAng))*(x - x1) + valHeightProfData[i-1] - ipStart = i - 1 - break - x1 = x2 - ofst = 2*ix + (2*optSlopeErr.nx)*iy - optSlopeErr.arTr[ofst] = 1. #Amplitude Transmission - optSlopeErr.arTr[ofst + 1] = 0. #Optical Path Difference - if(hApprox != 0): - optSlopeErr.arTr[ofst + 1] = -2*sinAng*hApprox #Optical Path Difference (to check sign!) - #print(ix, iy, optSlopeErr.arTr[ofst + 1]) - x += xStep - y += yStep - -#**********************Input Parameters and structures: - +print('Simulating propagation of a Coherent Gaussian X-ray beam through a Beamline containing Imperfect Mirrors') + +#**********************Input Parameters and Structures +#***********Folder and Data File Names strDataFolderName = 'data_example_09' #data sub-folder name +strMirSurfHeightErrInFileName01 = 'mirror1.dat' #mirror surface height error input file name +strMirOptPathDifOutFileName01 = 'ex09_res_opt_path_dif_er_m1.dat' #optical path difference due to mirror surface height error output file name +strMirOptPathDifOutFileName02 = 'ex09_res_opt_path_dif_er_vfm.dat' #optical path difference due to mirror surface height error output file name +strMirOptPathDifOutFileName03 = 'ex09_res_opt_path_dif_er_hfm.dat' #optical path difference due to mirror surface height error output file name +strIntInitOutFileName01 = 'ex09_res_int_in.dat' #initial wavefront intensity distribution output file name +strPhaseInitOutFileName01 = 'ex09_res_phase_in.dat' #initial wavefront phase output file name +strIntPropOutFileName01 = 'ex09_res_int_prop.dat' #propagated wavefront intensity distribution output file name +strPhasePropOutFileName01 = 'ex09_res_phase_prop.dat' #propagated wavefront phase output file name +#***********Gaussian Beam Source GsnBm = SRWLGsnBm() #Gaussian Beam structure (just parameters) -GsnBm.x = 0 #Transverse Coordinates of Gaussian Beam Center at Waist [m] +GsnBm.x = 0 #Transverse Positions of Gaussian Beam Center at Waist [m] GsnBm.y = 0 -GsnBm.z = 0 #Longitudinal Coordinate of Waist [m] +GsnBm.z = 0 #Longitudinal Position of Waist [m] GsnBm.xp = 0 #Average Angles of Gaussian Beam at Waist [rad] GsnBm.yp = 0 -GsnBm.avgPhotEn = 12400 #5000 #Photon Energy [eV] +GsnBm.avgPhotEn = 12400 #Photon Energy [eV] GsnBm.pulseEn = 0.001 #Energy per Pulse [J] - to be corrected GsnBm.repRate = 1 #Rep. Rate [Hz] - to be corrected GsnBm.polar = 1 #1- linear hoirizontal GsnBm.sigX = 23e-06/2.35 #Horiz. RMS size at Waist [m] GsnBm.sigY = GsnBm.sigX #Vert. RMS size at Waist [m] + +constConvRad = 1.23984186e-06/(4*3.1415926536) +rmsAngDiv = constConvRad/(GsnBm.avgPhotEn*GsnBm.sigX) #RMS angular divergence [rad] +print('RMS Source Size:', round(GsnBm.sigX*1.e+06, 3), 'micro-m; RMS Divergence:', round(rmsAngDiv*1.e+06, 3), 'micro-rad') + GsnBm.sigT = 10e-15 #Pulse duration [fs] (not used?) GsnBm.mx = 0 #Transverse Gauss-Hermite Mode Orders GsnBm.my = 0 +#***********Initial Wavefront wfr = SRWLWfr() #Initial Electric Field Wavefront wfr.allocate(1, 100, 100) #Numbers of points vs Photon Energy (1), Horizontal and Vertical Positions (dummy) -wfr.mesh.zStart = 270 #Longitudinal Position [m] at which Electric Field has to be calculated, i.e. the position of the first optical element +wfr.mesh.zStart = 270 #Longitudinal Position [m] at which initial Electric Field has to be calculated, i.e. the position of the first optical element wfr.mesh.eStart = GsnBm.avgPhotEn #Initial Photon Energy [eV] wfr.mesh.eFin = GsnBm.avgPhotEn #Final Photon Energy [eV] -firstHorAp = 1.44e-03 #First Aperture [m] -firstVertAp = 1.448e-03 #[m] (dummy?) + +wfr.unitElFld = 2 #Electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) + +distSrc_M1 = wfr.mesh.zStart - GsnBm.z +#Horizontal and Vertical Position Range for the Initial Wavefront calculation +#can be used to simulate the First Aperture (of M1) +firstHorAp = 8.*rmsAngDiv*distSrc_M1 #[m] +firstVertAp = firstHorAp #[m] + wfr.mesh.xStart = -0.5*firstHorAp #Initial Horizontal Position [m] wfr.mesh.xFin = 0.5*firstHorAp #Final Horizontal Position [m] wfr.mesh.yStart = -0.5*firstVertAp #Initial Vertical Position [m] wfr.mesh.yFin = 0.5*firstVertAp #Final Vertical Position [m] -sampFactNxNyForProp = 1.5 #sampling factor for adjusting nx, ny (effective if > 0) +sampFactNxNyForProp = 2 #sampling factor for adjusting nx, ny (effective if > 0) arPrecPar = [sampFactNxNyForProp] wfr.partBeam.partStatMom1.x = GsnBm.x #Some information about the source in the Wavefront structure @@ -160,54 +76,93 @@ def AuxTransmAddSurfHeightProfile(optSlopeErr, heightProfData, dim, ang): wfr.partBeam.partStatMom1.xp = GsnBm.xp wfr.partBeam.partStatMom1.yp = GsnBm.yp -#**********************Calculating Initial Wavefront and extracting Intensity: -srwl.CalcElecFieldGaussian(wfr, GsnBm, arPrecPar) -arI = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data -srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) #extracts intensity -AuxSaveIntData(arI, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_in.dat")) - -arP = array('d', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') -srwl.CalcIntFromElecField(arP, wfr, 6, 4, 3, wfr.mesh.eStart, 0, 0) #extracts radiation phase -AuxSaveIntData(arP, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_in.dat")) - -#***********Optical Elements -opDrM1_VFM = SRWLOptD(930 - 270 - 1.7) #Drift space from First Mirrors to KB - -#read mirror slope arror data from file and setup the corresponding optical element -print('Defining Trnansmission element (to simulate mirror surface slope error)...', end='') -opTrErM1 = SRWLOptT(100, 1500, firstHorAp, firstVertAp) -heightProfData = AuxReadInDataColumns(os.path.join(os.getcwd(), strDataFolderName, "mirror1.dat"), 2, '\t') -AuxTransmAddSurfHeightProfile(opTrErM1, heightProfData, 'y', 1.8e-03) +#***********Optical Elements and Propagation Parameters +#Sequence of Optical Elements: +# +# +# +# +# +# +# +# +# +# + +distM1_VFM = 658.3 #Distance from M1 to VFM [m] +distVFM_HFM = 0.6 #Distance from VFM to HFM [m] +distHFM_Samp = 1.1 #Distance from HFM to Sample [m] + +lenM1 = 0.5 #Length of M1 [m] +angM1 = 1.8e-3 #Incident Angle of M1 [rad] + +lenKB = 0.5 #Length of VFM and HFM (same for each) [m] +angKB = 3.6e-3 #Incident Angle of VFM and HFM [rad] + +#Aperture of M1 +opApM1 = SRWLOptA('r', 'a', 10.e-03, lenM1*angM1) + +#M1 Surface Height Error +#Read mirror slope arror data from file and setup the corresponding optical element +print('Defining Transmission element (to simulate mirror surface slope error)...', end='') +heightProfData = srwl_uti_read_data_cols(os.path.join(os.getcwd(), strDataFolderName, strMirSurfHeightErrInFileName01), _str_sep='\t', _i_col_start=0, _i_col_end=1) +opTrErM1 = srwl_opt_setup_surf_height_1d(heightProfData, _dim='y', _ang=angM1, _amp_coef=1) +#Use _amp_coef != 1 to scale surface height error print('done') print('Saving optical path difference data to file (for viewing/debugging)...', end='') -AuxSaveOpTransmData(opTrErM1, 3, os.path.join(os.getcwd(), strDataFolderName, "res_opt_path_dif_er_m1.dat")) +opPathDifErM1 = opTrErM1.get_data(3, 3) +srwl_uti_save_intens_ascii(opPathDifErM1, opTrErM1.mesh, os.path.join(os.getcwd(), strDataFolderName, strMirOptPathDifOutFileName01), 0, + ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) print('done') -opApKB = SRWLOptA('r', 'a', 1.98e-03, 1.98e-03) #Aperture of KB system +#Drift from M1 to VFH +opDrM1_VFM = SRWLOptD(distM1_VFM) -opLenVFM = SRWLOptL(1.e+20, 1.69689) #VFM simulated by Ideal Lens -print('Defining Trnansmission element (to simulate mirror surface slope error)...', end='') -opTrErVFM = SRWLOptT(100, 1500, 1.98e-03, 1.98e-03) -AuxTransmAddSurfHeightProfile(opTrErVFM, heightProfData, 'y', 3.6e-3) +#Aperture of KB system +opApKB = SRWLOptA('r', 'a', lenKB*angKB, lenKB*angKB) + +#VFM simulated by Ideal Lens: +#opVFM = SRWLOptL(_Fy=(distSrc_M1 + distM1_VFM)*(distVFM_HFM + distHFM_Samp)/(distSrc_M1 + distM1_VFM + distVFM_HFM + distHFM_Samp)) +#VFM simulated by Extended Elliptical Mirror: +opVFM = SRWLOptMirEl(_p=(distSrc_M1 + distM1_VFM), _q=(distVFM_HFM + distHFM_Samp), _ang_graz=angKB, _size_tang=lenKB, _size_sag=10.e-03, + _nvx=0, _nvy=cos(angKB), _nvz=-sin(angKB), _tvx=0, _tvy=-sin(angKB)) + +#VFM Surface Height Error +print('Defining Transmission element (to simulate mirror surface slope error)...', end='') +opTrErVFM = srwl_opt_setup_surf_height_1d(heightProfData, _dim='y', _ang=angKB, _amp_coef=1) +#Use _amp_coef != 1 to scale surface height error print('done') print('Saving optical path difference data to file (for viewing/debugging)...', end='') -AuxSaveOpTransmData(opTrErVFM, 3, os.path.join(os.getcwd(), strDataFolderName, "res_opt_path_dif_er_vfm.dat")) +opPathDifErVFM = opTrErVFM.get_data(3, 3) +opPathDifErVFMy = opTrErVFM.get_data(3, 2) #for plotting +srwl_uti_save_intens_ascii(opPathDifErVFM, opTrErVFM.mesh, os.path.join(os.getcwd(), strDataFolderName, strMirOptPathDifOutFileName02), 0, + ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) print('done') -opDrVFM_HFM = SRWLOptD(0.6) #Drift space between VFM and HFM +#Drift from VFM to HFM +opDrVFM_HFM = SRWLOptD(distVFM_HFM) -opLenHFM = SRWLOptL(1.0987, 1.e+20) #HFM simulated by Ideal Lens -print('Defining Trnansmission element (to simulate mirror surface slope error)...', end='') -opTrErHFM = SRWLOptT(1500, 100, 1.98e-03, 1.98e-03) -AuxTransmAddSurfHeightProfile(opTrErHFM, heightProfData, 'x', 3.6e-3) +#HFM simulated by Ideal Lens: +#opHFM = SRWLOptL(_Fx=(distSrc_M1 + distM1_VFM + distVFM_HFM)*distHFM_Samp/(distSrc_M1 + distM1_VFM + distVFM_HFM + distHFM_Samp)) +#VFM simulated by Extended Elliptical Mirror: +opHFM = SRWLOptMirEl(_p=(distSrc_M1 + distM1_VFM + distVFM_HFM), _q=distHFM_Samp, _ang_graz=angKB, _size_tang=lenKB, _size_sag=10.e-03, + _nvx=cos(angKB), _nvy=0, _nvz=-sin(angKB), _tvx=-sin(angKB), _tvy=0) + +#HFM Surface Height Error +print('Defining Transmission element (to simulate mirror surface slope error)...', end='') +opTrErHFM = srwl_opt_setup_surf_height_1d(heightProfData, _dim='x', _ang=angKB, _amp_coef=1) +#Use _amp_coef != 1 to scale surface height error print('done') print('Saving optical path difference data to file (for viewing/debugging)...', end='') -AuxSaveOpTransmData(opTrErHFM, 3, os.path.join(os.getcwd(), strDataFolderName, "res_opt_path_dif_er_hfm.dat")) +opPathDifErHFM = opTrErHFM.get_data(3, 3) +srwl_uti_save_intens_ascii(opPathDifErHFM, opTrErHFM.mesh, os.path.join(os.getcwd(), strDataFolderName, strMirOptPathDifOutFileName03), 0, + ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) print('done') -opDrHFM_Samp = SRWLOptD(1.1) #Drift space from First Mirrors to KB +#Drift from HFM to Sample +opDrHFM_Samp = SRWLOptD(distHFM_Samp) -#***********Wavefront Propagation Parameters: +#Wavefront Propagation Parameters: #[0]: Auto-Resize (1) or not (0) Before propagation #[1]: Auto-Resize (1) or not (0) After propagation #[2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) @@ -220,28 +175,87 @@ def AuxTransmAddSurfHeightProfile(optSlopeErr, heightProfData, dim, ang): #[9]: Type of wavefront Shift before Resizing (not yet implemented) #[10]: New Horizontal wavefront Center position after Shift (not yet implemented) #[11]: New Vertical wavefront Center position after Shift (not yet implemented) -prParRes1 = [0, 0, 1., 1, 0, 3., 1.0, 3., 1.0, 0, 0, 0] -prParRes2 = [0, 0, 1., 1, 0, 0.6, 8.0, 0.6, 4.0, 0, 0, 0] -prParRes0 = [0, 0, 1., 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] -prParRes3 = [0, 0, 1., 1, 0, 0.04, 5.0, 0.04, 5.0, 0, 0, 0] +# [0][1][2] [3][4] [5] [6] [7] [8] [9][10][11] +#prParInit = [0, 0, 1., 1, 0, 2., 5., 2., 3., 0, 0, 0] +prParInit = [0, 0, 1., 1, 0, 2., 5., 6., 3., 0, 0, 0] +prPar0 = [0, 0, 1., 1, 0, 1., 1., 1., 1., 0, 0, 0] +#prParPost = [0, 0, 1., 1, 0, 0.06, 3., 0.1, 2., 0, 0, 0] +prParPost = [0, 0, 1., 1, 0, 0.06, 3., 0.04, 2., 0, 0, 0] #Post-propagation resizing parameters + +#NOTE: in this case of simulation, it can be enough to define the precision parameters only Before and After +#the propagation through the entire Beamline. However, if necessary, different propagation parameters can be specified +#for each optical element. +#The optimal values of propagation parameters may depend on photon energy and optical layout. + +#"Beamline" - a sequenced Container of Optical Elements (together with the corresponding wavefront propagation parameters, +#and the "post-propagation" wavefront resizing parameters for better viewing). +optBL = SRWLOptC([opApM1, opTrErM1, opDrM1_VFM, opApKB, opVFM, opTrErVFM, opDrVFM_HFM, opHFM, opTrErHFM, opDrHFM_Samp], + [prParInit, prPar0, prPar0, prPar0, prPar0, prPar0, prPar0, prPar0, prPar0, prPar0, prParPost]) + +#**********************Calculation +#***********Initial Wavefront of Gaussian Beam +#Initial Wavefront and extracting Intensity: +srwl.CalcElecFieldGaussian(wfr, GsnBm, arPrecPar) +mesh0 = deepcopy(wfr.mesh) +arI0 = array('f', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D intensity data +srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, mesh0.eStart, 0, 0) #extracts intensity +srwl_uti_save_intens_ascii(arI0, mesh0, os.path.join(os.getcwd(), strDataFolderName, strIntInitOutFileName01), 0, + ['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Spectral Fluence'], _arUnits=['eV', 'm', 'm', 'J/eV/mm^2']) -#"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) -optBL = SRWLOptC([opTrErM1, opDrM1_VFM, opApKB, opLenVFM, opTrErVFM, opDrVFM_HFM, opLenHFM, opTrErHFM, opDrHFM_Samp], - [prParRes1, prParRes0, prParRes2, prParRes0, prParRes0, prParRes0, prParRes0, prParRes0, prParRes0, prParRes3]) +arI0x = array('f', [0]*mesh0.nx) #array to take 1D intensity data (for plotting) +srwl.CalcIntFromElecField(arI0x, wfr, 6, 0, 1, mesh0.eStart, 0, 0) #extracts intensity +arI0y = array('f', [0]*mesh0.ny) #array to take 1D intensity data +srwl.CalcIntFromElecField(arI0y, wfr, 6, 0, 2, mesh0.eStart, 0, 0) #extracts intensity + +arP0 = array('d', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D phase data (note it should be 'd') +srwl.CalcIntFromElecField(arP0, wfr, 6, 4, 3, mesh0.eStart, 0, 0) #extracts radiation phase +srwl_uti_save_intens_ascii(arP0, mesh0, os.path.join(os.getcwd(), strDataFolderName, strPhaseInitOutFileName01), 0, + ['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['eV', 'm', 'm', 'rad']) #***********Wavefront Propagation print('Propagating wavefront...', end='') +t0 = time.time(); srwl.PropagElecField(wfr, optBL) -print('done') +print('done in', round(time.time() - t0), 's') print('Saving propagated wavefront intensity and phase to files...', end='') -arI = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data -srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) #extracts intensity -AuxSaveIntData(arI, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_int_prop.dat")) +mesh1 = deepcopy(wfr.mesh) +arI1 = array('f', [0]*mesh1.nx*mesh1.ny) #"flat" array to take 2D intensity data +srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, mesh1.eStart, 0, 0) #extracts intensity +srwl_uti_save_intens_ascii(arI1, mesh1, os.path.join(os.getcwd(), strDataFolderName, strIntPropOutFileName01), 0, + ['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Spectral Fluence'], _arUnits=['eV', 'm', 'm', 'J/eV/mm^2']) + +arI1x = array('f', [0]*mesh1.nx) #array to take 1D intensity data (for plotting) +srwl.CalcIntFromElecField(arI1x, wfr, 6, 0, 1, mesh1.eStart, 0, 0) #extracts intensity +arI1y = array('f', [0]*mesh1.ny) #array to take 1D intensity data +srwl.CalcIntFromElecField(arI1y, wfr, 6, 0, 2, mesh1.eStart, 0, 0) #extracts intensity -arP = array('d', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D phase data (note it should be 'd') -srwl.CalcIntFromElecField(arP, wfr, 6, 4, 3, wfr.mesh.eStart, 0, 0) #extracts radiation phase -AuxSaveIntData(arP, wfr.mesh, os.path.join(os.getcwd(), strDataFolderName, "res_phase_prop.dat")) +arP1 = array('d', [0]*mesh1.nx*mesh1.ny) #"flat" array to take 2D phase data (note it should be 'd') +srwl.CalcIntFromElecField(arP1, wfr, 6, 4, 3, mesh1.eStart, 0, 0) #extracts radiation phase +srwl_uti_save_intens_ascii(arP1, mesh1, os.path.join(os.getcwd(), strDataFolderName, strPhasePropOutFileName01), 0, + ['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Phase'], _arUnits=['eV', 'm', 'm', 'rad']) print('done') +#**********************Plotting Results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close any graph windows to proceed) ... ', end='') +plotMesh0x = [1000*mesh0.xStart, 1000*mesh0.xFin, mesh0.nx] +plotMesh0y = [1000*mesh0.yStart, 1000*mesh0.yFin, mesh0.ny] +uti_plot2d(arI0, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Spectral Fluence Before Propagation']) +uti_plot1d(arI0x, plotMesh0x, ['Horizontal Position [mm]', 'Spectral Fluence [J/eV/mm^2]', 'Spectral Fluence (horizontal cut at y = 0)']) +uti_plot1d(arI0y, plotMesh0y, ['Vertical Position [mm]', 'Spectral Fluence [J/eV/mm^2]', 'Spectral Fluence (vertical cut at x = 0)']) +#uti_plot2d(arP0, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Phase Before Propagation']) +plotMirErrMesh0x = [1000*opTrErVFM.mesh.xStart, 1000*opTrErVFM.mesh.xFin, opTrErVFM.mesh.nx] +plotMirErrMesh0y = [1000*opTrErVFM.mesh.yStart, 1000*opTrErVFM.mesh.yFin, opTrErVFM.mesh.ny] +uti_plot2d(opPathDifErVFM, plotMirErrMesh0x, plotMirErrMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Optical Path Difference due to VFM Error']) +uti_plot1d(opPathDifErVFMy, plotMirErrMesh0y, ['Vertical Position [mm]', 'Opt. Path. Diff. [m]', 'Optical Path Difference']) + +plotMesh1x = [1e+06*mesh1.xStart, 1e+06*mesh1.xFin, mesh1.nx] +plotMesh1y = [1e+06*mesh1.yStart, 1e+06*mesh1.yFin, mesh1.ny] +uti_plot2d(arI1, plotMesh1x, plotMesh1y, ['Horizontal Position [um]', 'Vertical Position [um]', 'Spectral Fluence After Propagation']) +uti_plot1d(arI1x, plotMesh1x, ['Horizontal Position [um]', 'Spectral Fluence [J/eV/mm^2]', 'Spectral Fluence (horizontal cut at y = 0)']) +uti_plot1d(arI1y, plotMesh1y, ['Vertical Position [um]', 'Spectral Fluence [J/eV/mm^2]', 'Spectral Fluence (vertical cut at x = 0)']) +#uti_plot2d(arP1, plotMesh1x, plotMesh1y, ['Horizontal Position [um]', 'Vertical Position [um]', 'Phase After Propagation']) + +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) +print('done') diff --git a/env/release/srw_python/SRWLIB_Example10.py b/env/release/srw_python/SRWLIB_Example10.py index 6c55cccf..adab7963 100644 --- a/env/release/srw_python/SRWLIB_Example10.py +++ b/env/release/srw_python/SRWLIB_Example10.py @@ -2,13 +2,12 @@ ############################################################################# # SRWLIB Example # 10: Simulating emission and propagation of partially-coherent undulator radiation # through a microscopy beamline with a secondary source aperture and ellopsoidal K-B mirrors used for final focusing -# v 0.02 +# v 0.07 ############################################################################# from __future__ import print_function #Python 2.7 compatibility from srwlib import * import os -import sys import time print('SRWLIB Python Example # 10:') @@ -19,7 +18,7 @@ print('After this, calculation of partially-coherent UR from entire electron beam is started as a loop over "macro-electrons", using "srwl_wfr_emit_prop_multi_e" function. ', end='') print('This function can run either in "normal" sequential mode, or in parallel mode under "mpi4py".', end='') print('For this, an MPI2 package and the "mpi4py" Python package have to be installed and configured, and this example has to be started e.g. as:') -print(' mpiexec -n 5 python SRWLIB_Example08.py') +print(' mpiexec -n 5 python SRWLIB_Example10.py') print('For more information on parallel calculations under "mpi4py" please see documentation to the "mpi4py" and MPI.') print('Note that the long-lasting partially-coherent UR calculation saves from time to time instant average intensity to an ASCII file, ', end='') print('so the execution of the long loop over "macro-electrons" can be aborted after some time without the danger that all results will be lost.') @@ -27,9 +26,9 @@ #**********************Input Parameters: strExDataFolderName = 'data_example_10' #example data sub-folder name -strIntSE_OutFileName = 'res_int_se.dat' #file name for output initial single-electron SR intensity data -strIntPropSE_OutFileName = 'res_int_prop_se.dat' #file name for output propagated single-electron SR intensity data -strIntPropME_OutFileName = 'res_int_prop_me.dat' #file name for output propagated multi-electron SR intensity data +strIntSE_OutFileName = 'ex10_res_int_se.dat' #file name for output initial single-electron SR intensity data +strIntPropSE_OutFileName = 'ex10_res_int_prop_se.dat' #file name for output propagated single-electron SR intensity data +strIntPropME_OutFileName = 'ex10_res_int_prop_me.dat' #file name for output propagated multi-electron SR intensity data #***********Undulator numPer = 71.5 #Number of ID Periods (without counting for terminations @@ -47,7 +46,7 @@ #***********Electron Beam elecBeam = SRWLPartBeam() elecBeam.Iavg = 0.5 #Average Current [A] -elecBeam.partStatMom1.x = 0.e-06 #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] +elecBeam.partStatMom1.x = 0. #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] elecBeam.partStatMom1.y = 0. #-0.00025 elecBeam.partStatMom1.z = 0. #-0.5*undPer*(numPer + 4) #Initial Longitudinal Coordinate (set before the ID) elecBeam.partStatMom1.xp = 0. #Initial Relative Transverse Velocities @@ -67,9 +66,10 @@ relPrec = 0.01 #relative precision zStartInteg = 0 #longitudinal position to start integration (effective if < zEndInteg) zEndInteg = 0 #longitudinal position to finish integration (effective if > zStartInteg) -npTraj = 20000 -sampFactNxNyForProp = 0.2 #0.1 #sampling factor for adjusting nx, ny (effective if > 0) -arPrecParSpec = [meth, relPrec, zStartInteg, zEndInteg, npTraj, 0, 0] +npTraj = 20000 #Number of points for trajectory calculation +useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) +sampFactNxNyForProp = 0.2 #0.6 #sampling factor for adjusting nx, ny (effective if > 0) +arPrecParSpec = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, 0] #****************** Initial Wavefront wfr = SRWLWfr() #For intensity distribution at fixed photon energy @@ -77,20 +77,43 @@ wfr.mesh.zStart = 20 #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated wfr.mesh.eStart = 12700 #Initial Photon Energy [eV] wfr.mesh.eFin = wfr.mesh.eStart #Final Photon Energy [eV] -wfr.mesh.xStart = -0.0004 #Initial Horizontal Position [m] -wfr.mesh.xFin = 0.0004 #Final Horizontal Position [m] -wfr.mesh.yStart = -0.00025 #Initial Vertical Position [m] -wfr.mesh.yFin = 0.00025 #Final Vertical Position [m] +wfr.mesh.xStart = -0.0004 #-0.00015 #Initial Horizontal Position [m] +wfr.mesh.xFin = 0.0004 #0.00015 #Final Horizontal Position [m] +wfr.mesh.yStart = -0.00025 #-0.00015 #Initial Vertical Position [m] +wfr.mesh.yFin = 0.00025 #0.00015 #Final Vertical Position [m] meshInitPartCoh = deepcopy(wfr.mesh) wfr.partBeam = elecBeam #***************** Optical Elements and Propagation Parameters Drift_Slits_HFM = SRWLOptD(22.) #Drift from first Slits to Horizontally-Focusing Mirror (HFM) + HFM = SRWLOptL(9.92727) #HFM as Thin Lens + Drift_HFM_SSA = SRWLOptD(13.) #Drift from HFM to Secondary Source Aperture (SSA) + SSA = SRWLOptA('r', 'a', 30e-06, 10e-03) + Drift_SSA_VKB = SRWLOptD(11.) #Drift from SSA to Center of Vertically Focusing K-B Mirror (VKB) + +twoSlitPlane = None #'h' #'v' #plane for the two slit interference scheme (should be 'h' or 'v' for calculating interference) +#twoSlitInterfAngRepres = False #calculate interference in angular representation +twoSlitSep = 0.2e-03 #separation distance between two slits +twoSlitSize = 0.002e-03 #size of each slit +twoSlitObstaclePos = 0 #0.0021e-03 #center position of obstacle (e.g. for calculating diffraction on 1 slit) + +TwoSlit_Drift = SRWLOptD(20.) #Drift space after 2 slits + +twoSlitSizeAp = twoSlitSep + twoSlitSize +twoSlitSizeOb = twoSlitSep - twoSlitSize +TwoSlit_Ap = None; TwoSlit_Ob = None; +if twoSlitPlane == 'h': + TwoSlit_Ap = SRWLOptA('r', 'a', twoSlitSizeAp, 10e-03) + TwoSlit_Ob = SRWLOptA('r', 'o', twoSlitSizeOb, 10e-03, twoSlitObstaclePos, 0) +elif twoSlitPlane == 'v': + TwoSlit_Ap = SRWLOptA('r', 'a', 10e-03, twoSlitSizeAp) + TwoSlit_Ob = SRWLOptA('r', 'o', 10e-03, twoSlitSizeOb, 0, twoSlitObstaclePos) + ApKB = SRWLOptA('r', 'a', 1.25e-03, 1.25e-03) #Aperture Before K-B angVKB = 2.5e-03 #grazing angle at VKB center [rad] @@ -100,16 +123,29 @@ angHKB = 2.5e-03 #[rad] HKB = SRWLOptMirEl(_p=11.5, _q=0.5, _ang_graz=angHKB, _r_sag=1.e+40, _size_tang=0.5, _nvx=cos(angHKB), _nvy=0, _nvz=-sin(angHKB), _tvx=-sin(angHKB), _tvy=0, _x=0, _y=0, _treat_in_out=1) #HKB Ellipsoidal Mirror +#HKB = SRWLOptL(_Fx=11.5*0.5/(11.5 + 0.5)) Drift_HKB_Sample = SRWLOptD(0.5) #Drift from HKB Center to Sample #Wavefront Propagation Parameters: # [ 0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] -ppDrift_Slits_HFM = [ 0, 0, 1.0, 1, 0, 4.0, 4.0, 3.0, 4.0, 0, 0, 0] +ppDrift_Slits_HFM = [ 0, 0, 1.0, 1, 0, 4.0, 4.0, 3.0, 3.0, 0, 0, 0] ppHFM = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] ppDrift_HFM_SSA = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] -ppSSA = [ 0, 0, 1.0, 0, 0, 1.0, 3.0, 1.0, 4.0, 0, 0, 0] +#ppSSA = [ 0, 0, 1.0, 0, 0, 1.0, 3.0, 1.0, 1.0, 0, 0, 0] +ppSSA = [ 0, 0, 1.0, 0, 0, 1.0, 6.0, 1.0, 1.0, 0, 0, 0] ppDrift_SSA_VKB = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] + +ppTwoSlit_Ap = None +if twoSlitPlane == 'h': + ppTwoSlit_Ap = [ 0, 0, 1.0, 1, 0, 0.5, 7.0, 0.5, 0.5, 0, 0, 0] + #ppTwoSlit_Ap = [ 0, 0, 1.0, 1, 0, 1.0, 30.0, 1.0, 1.0, 0, 0, 0] +elif twoSlitPlane == 'v': + ppTwoSlit_Ap = [ 0, 0, 1.0, 1, 0, 0.5, 0.04, 0.8, 40.0, 0, 0, 0] + #ppTwoSlit_Ap = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 40.0, 0, 0, 0] +ppTwoSlit_Ob = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] +ppTwoSlit_Drift = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] + ppApKB = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] ppVKB = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] ppDrift_VKB_HKB = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] @@ -131,11 +167,16 @@ #[11]: New Vertical wavefront Center position after Shift (not yet implemented) #"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) -optBL = SRWLOptC([Drift_Slits_HFM, HFM, Drift_HFM_SSA, SSA, Drift_SSA_VKB, ApKB, VKB, Drift_VKB_HKB, HKB, Drift_HKB_Sample], - [ppDrift_Slits_HFM, ppHFM, ppDrift_HFM_SSA, ppSSA, ppDrift_SSA_VKB, ppApKB, ppVKB, ppDrift_VKB_HKB, ppHKB, ppDrift_HKB_Sample, ppFinal]) +if (twoSlitPlane == 'h') or (twoSlitPlane == 'v'): + optBL = SRWLOptC([Drift_Slits_HFM, HFM, Drift_HFM_SSA, SSA, Drift_SSA_VKB, TwoSlit_Ap, TwoSlit_Ob, TwoSlit_Drift],# ApKB, VKB, Drift_VKB_HKB, HKB, Drift_HKB_Sample], + [ppDrift_Slits_HFM, ppHFM, ppDrift_HFM_SSA, ppSSA, ppDrift_SSA_VKB, ppTwoSlit_Ap, ppTwoSlit_Ob, ppTwoSlit_Drift])#, ppApKB, ppVKB, ppDrift_VKB_HKB, ppHKB, ppDrift_HKB_Sample, ppFinal]) +else: + optBL = SRWLOptC([Drift_Slits_HFM, HFM, Drift_HFM_SSA, SSA, Drift_SSA_VKB, ApKB, VKB, Drift_VKB_HKB, HKB, Drift_HKB_Sample], + [ppDrift_Slits_HFM, ppHFM, ppDrift_HFM_SSA, ppSSA, ppDrift_SSA_VKB, ppApKB, ppVKB, ppDrift_VKB_HKB, ppHKB, ppDrift_HKB_Sample, ppFinal]) #**********************Calculation (SRWLIB function calls) if(srwl_uti_proc_is_master()): +#if(False): print(' Performing Initial Single-E Electric Field calculation ... ', end='') arPrecParSpec[6] = sampFactNxNyForProp #sampling factor for adjusting nx, ny (effective if > 0) srwl.CalcElecFieldSR(wfr, 0, magFldCnt, arPrecParSpec) @@ -144,26 +185,35 @@ arI = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" array to take 2D intensity data srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) print('done') - print(' Saving the Initial Electric Field into a file ... ', end='') + print(' Saving the Initial Wavefront Intensity into a file ... ', end='') srwl_uti_save_intens_ascii(arI, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntSE_OutFileName)) print('done') print(' Simulating Electric Field Wavefront Propagation ... ', end='') t0 = time.time(); srwl.PropagElecField(wfr, optBL) - print('done; lasted', time.time() - t0, 's') + print('done; lasted', round(time.time() - t0), 's') + + #if twoSlitInterfAngRepres: srwl.SetRepresElecField(wfr, 'a') + print(' Extracting Intensity from the Propagated Electric Field ... ', end='') arI1 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" 2D array to take intensity data srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) + #srwl.CalcIntFromElecField(arI1, wfr, 0, 6, 3, wfr.mesh.eStart, 0, 0) #test (E-field extraction) print('done') print(' Saving the Propagated Wavefront Intensity data to a file ... ', end='') srwl_uti_save_intens_ascii(arI1, wfr.mesh, os.path.join(os.getcwd(), strExDataFolderName, strIntPropSE_OutFileName)) print('done') -#sys.exit(0) - -print(' Starting simulation of Partially-Coherent Wavefront Propagation ... ') -radStokesProp = srwl_wfr_emit_prop_multi_e(elecBeam, magFldCnt, meshInitPartCoh, 1, 0.01, 50000, 5, 20, +#sys.exit() + +print(' Starting simulation of Partially-Coherent Wavefront Propagation (takes a lot of time)... ') +nMacroElec = 50000 #Total number of Macro-Electrons (Wavefronts) +nMacroElecAvgOneProc = 5 #Number of Macro-Electrons (Wavefronts) to average on each node (for MPI calculations) +nMacroElecSavePer = 5 #Saving periodicity (in terms of Macro-Electrons) for the Resulting Intensity +srCalcMeth = 1 #SR calculation method (1- undulator) +srCalcPrec = 0.01 #SR calculation rel. accuracy +radStokesProp = srwl_wfr_emit_prop_multi_e(elecBeam, magFldCnt, meshInitPartCoh, srCalcMeth, srCalcPrec, nMacroElec, nMacroElecAvgOneProc, nMacroElecSavePer, os.path.join(os.getcwd(), strExDataFolderName, strIntPropME_OutFileName), sampFactNxNyForProp, optBL) print('done') diff --git a/env/release/srw_python/SRWLIB_Example11.py b/env/release/srw_python/SRWLIB_Example11.py new file mode 100644 index 00000000..66945151 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example11.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLIB Example # 11: Calculating spectral flux of undulator radiation by finite-emittance electron beam +# and performing partially-coherent wavefront propagation through a simple optical system containing dispersive CRL +# v 0.03 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +import os +#import sys +import time + +print('SRWLIB Example # 11:') +print('Calculating spectral flux of undulator radiation by finite-emittance electron beam and performing partially-coherent wavefront propagation') +print('through a simple optical system containing dispersive CRL') + +#**********************Input Parameters: +strDataFolderName = 'data_example_11' #example data sub-folder name +strOptPathDifCRL_Be = 'ex11_res_opt_path_dif_crl_be.dat' #file name for optical path difference of Be CRL +strOptPathDifCRL_Al = 'ex11_res_opt_path_dif_crl_al.dat' #file name for optical path difference of Al CRL +strFluxOutFileName = 'ex11_res_multi_e_in_spec_flux.dat' #file name for output UR flux data +strTrjOutFileName = 'ex11_res_trj.dat' #file name for output trajectory data +strSingleElSpecOutFileName = 'ex11_res_single_e_spec.dat' #file name for output single-e spectrum data +strSingleElIntOutFileName = 'ex11_res_single_e_int.dat' #file name for output single-e intensity data +strSingleElPropIntOutFileName = 'ex11_res_single_e_prop_int.dat' #file name for output propagated single-e intensity data +strMultiElPropIntOutFileName = 'ex11_res_multi_e_prop_int.dat' #file name for output propagated multi-e intensity data +strSingleGausBeamIntOutFileName = 'ex11_res_single_g_int.dat' #file name for output single-e intensity data +strSingleGausBeamPropIntOutFileName = 'ex11_res_single_g_prop_int.dat' #file name for output propagated single-e intensity data +strMultiGausBeamPropIntOutFileName = 'ex11_res_multi_g_prop_int.dat' #file name for output propagated multi-e intensity data + +#***********Undulator +harmB = SRWLMagFldH() #magnetic field harmonic +harmB.n = 1 #harmonic number +harmB.h_or_v = 'v' #magnetic field plane: horzontal ('h') or vertical ('v') +harmB.B = 0.391486 #0.920902 #1. #magnetic field amplitude [T] +harmB.s = 0 #assuming anti-symmetric magnetic field vs long. pos. +und = SRWLMagFldU([harmB]) +und.per = 0.022 #0.02 #period length [m] +und.nPer = 92 #150 #number of periods (will be rounded to integer) + +xcID = 0 #Transverse Coordinates of Undulator Center [m] +ycID = 0 +zcID = 1.3695 #Longitudinal Coordinate of Undulator Center [m] + +magFldCnt = SRWLMagFldC([und], array('d', [xcID]), array('d', [ycID]), array('d', [zcID])) #Container of all magnetic field elements + +#***********Electron Beam +eBeam = SRWLPartBeam() +eBeam.Iavg = 0.1 #0.5 #average current [A] +eBeam.partStatMom1.x = 0. #initial transverse positions [m] +eBeam.partStatMom1.y = 0. +eBeam.partStatMom1.z = 0. #initial longitudinal positions (set in the middle of undulator) +eBeam.partStatMom1.xp = 0 #initial relative transverse velocities +eBeam.partStatMom1.yp = 0 +eBeam.partStatMom1.gamma = 6.04/0.5109989e-03 #relative energy +sigEperE = 0.001 #relative RMS energy spread +sigX = 100e-06 #33.33e-06 #horizontal RMS size of e-beam [m] +sigXp = 48.23e-06 #16.5e-06 #horizontal RMS angular divergence [rad] +sigY = 9.525e-06 #2.912e-06 #vertical RMS size of e-beam [m] +sigYp = 3.1623e-06 #2.7472e-06 #vertical RMS angular divergence [rad] +#2nd order stat. moments: +eBeam.arStatMom2[0] = sigX*sigX #<(x-)^2> +eBeam.arStatMom2[1] = 2.695e-09 #<(x-)(x'-)> [m] +eBeam.arStatMom2[2] = sigXp*sigXp #<(x'-)^2> +eBeam.arStatMom2[3] = sigY*sigY #<(y-)^2> +eBeam.arStatMom2[4] = 0.002695e-09 #<(y-)(y'-)> [m] +eBeam.arStatMom2[5] = sigYp*sigYp #<(y'-)^2> +eBeam.arStatMom2[10] = sigEperE*sigEperE #<(E-)^2>/^2 + +#***********Gaussian Beam (source option) +gBeam = SRWLGsnBm() #Gaussian Beam structure (just parameters) +gBeam.x = 0 #Transverse Coordinates of Gaussian Beam Center at Waist [m] +gBeam.y = 0 +gBeam.z = 0 #Longitudinal Coordinate of Waist [m] +gBeam.xp = 0 #Average Angles of Gaussian Beam at Waist [rad] +gBeam.yp = 0 +gBeam.avgPhotEn = 35.66e+03 #Photon Energy [eV] +gBeam.pulseEn = 0.001 #Energy per Pulse [J] - dummy +gBeam.repRate = 1 #Rep. Rate [Hz] - dummy +gBeam.polar = 1 #1- linear hoirizontal +gBeamWavelength = 1.239842e-06/gBeam.avgPhotEn +gBeamSigDiv = sqrt(gBeamWavelength/(2*und.per*und.nPer)) #Horiz. RMS angular divergence (close to the single-electron UR central cone size value) +gBeamSigSize = gBeamWavelength/(4*3.1416*gBeamSigDiv) #RMS size at Waist [m] (close to the single-electron UR central cone size value) +gBeam.sigX = gBeamSigSize #Horiz. RMS size at Waist [m] +gBeam.sigY = gBeamSigSize #Vert. RMS size at Waist [m] +#print('RMS size of Gaussian Beam at Waist: ', gBeam.sigX) +gBeam.sigT = 1e-27 #Pulse duration [fs] (to have large broadband) +gBeam.mx = 0 #Transverse Gauss-Hermite Mode Orders +gBeam.my = 0 + +#To edit: +srcToUse = 'e' #'e'- e-beam in undulator; 'g'- Gaussian Beam + +#***********Auxiliary Electron Trajectory structure (for test) +partTraj = SRWLPrtTrj() #defining auxiliary trajectory structure +partTraj.partInitCond = eBeam.partStatMom1 +partTraj.allocate(20001) +partTraj.ctStart = 0.2695 #Start "time" for the calculation +partTraj.ctEnd = 2.5 + +#***********Precision Parameters +arPrecF = [0]*5 #for spectral flux vs photon energy +arPrecF[0] = 1 #initial UR harmonic to take into account +arPrecF[1] = 9 #final UR harmonic to take into account +arPrecF[2] = 1. #longitudinal integration precision parameter +arPrecF[3] = 1. #azimuthal integration precision parameter +arPrecF[4] = 1 #calculate flux within aperture (1) or flux per unit surface (2) + +arPrecP = [0]*5 #for power density +arPrecP[0] = 1.5 #precision factor +arPrecP[1] = 1 #power density computation method (1- "near field", 2- "far field") +arPrecP[2] = 0 #initial longitudinal position (effective if arPrecP[2] < arPrecP[3]) +arPrecP[3] = 0 #final longitudinal position (effective if arPrecP[2] < arPrecP[3]) +arPrecP[4] = 20000 #number of points for (intermediate) trajectory calculation + +arPrecS = [0]*7 #for electric field and single-electron intensity spectrum +arPrecS[0] = 1 #SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" +arPrecS[1] = 0.01 #relative precision +arPrecS[2] = 0 #longitudinal position to start integration (effective if < zEndInteg) +arPrecS[3] = 0 #longitudinal position to finish integration (effective if > zStartInteg) +arPrecS[4] = 20000 #Number of points for intermediate trajectory calculation +arPrecS[5] = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) +arPrecS[6] = -1 #sampling factor for adjusting nx, ny (effective if > 0) + +sampFactNxNyForProp = 0.15 #0.1 #sampling factor for adjusting nx, ny (effective if > 0) +arPrecI = deepcopy(arPrecS) #for electric field and single-electron intensity (initial wavefront) +arPrecI[6] = sampFactNxNyForProp + +arPrecG = [sampFactNxNyForProp] #for Gaussian Beam +#sys.exit(0) + +#***********Defining mesh and allocating memory for UR Stokes parameters and Power Density distributions +stkF = SRWLStokes() #for spectral flux vs photon energy +stkF.allocate(2000, 1, 1) #numbers of points vs photon energy, horizontal and vertical positions +stkF.mesh.zStart = 32.87 #longitudinal position [m] at which UR has to be calculated +stkF.mesh.eStart = 10. #initial photon energy [eV] +stkF.mesh.eFin = 40.e+03 #20000. #final photon energy [eV] +stkF.mesh.xStart = -0.0005 #initial horizontal position of the collection aperture [m] +stkF.mesh.xFin = 0.0005 #final horizontal position of the collection aperture [m] +stkF.mesh.yStart = -0.0005 #initial vertical position of the collection aperture [m] +stkF.mesh.yFin = 0.0005 #final vertical position of the collection aperture [m] + +wfrS = SRWLWfr() #For on-axis single-electron intensity vs photon energy +wfrS.allocate(10000, 1, 1) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions +wfrS.mesh.zStart = stkF.mesh.zStart #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated +wfrS.mesh.eStart = stkF.mesh.eStart #Initial Photon Energy [eV] +wfrS.mesh.eFin = stkF.mesh.eFin #Final Photon Energy [eV] +wfrS.mesh.xStart = 0 #Initial Horizontal Position [m] +wfrS.mesh.xFin = 0 #Final Horizontal Position [m] +wfrS.mesh.yStart = 0 #Initial Vertical Position [m] +wfrS.mesh.yFin = 0 #Final Vertical Position [m] +wfrS.partBeam = eBeam + +wfrI = SRWLWfr() #For single-electron intensity at fixed photon energy +wfrI.allocate(1, 201, 201) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions +wfrI.mesh.zStart = stkF.mesh.zStart #Longitudinal Position [m] from Center of Straight Section at which SR has to be calculated +wfrI.mesh.eStart = 35.66e+03 #35.3e+03 #Initial Photon Energy [eV] +wfrI.mesh.eFin = wfrI.mesh.eStart #Final Photon Energy [eV] +wfrI.mesh.xStart = stkF.mesh.xStart #Initial Horizontal Position [m] +wfrI.mesh.xFin = stkF.mesh.xFin #Final Horizontal Position [m] +wfrI.mesh.yStart = stkF.mesh.yStart #Initial Vertical Position [m] +wfrI.mesh.yFin = stkF.mesh.yFin #Final Vertical Position [m] +wfrI.partBeam = eBeam +auxMeshP = deepcopy(wfrI.mesh) + +#***********Defining optical elements + +#Defining a perfect 2D parabolic CRL (with dispersion): +#Be CRL array, 5 m focusing distance 905 m +print('Setting-up CRL (with dispersion)...') +eStartCRL = 34.01e+03 # Initial Photon Energy [eV] +eFinCRL = 36.11e+03 #Final Photon Energy [eV] +#Refractive Index Decrement tabulated (with constant step) for the photon energy from eStartCRL to eFinCRL +arDeltaBe = [2.93914e-07, 2.92193e-07, 2.90487e-07, 2.88796e-07, 2.8712e-07, 2.85458e-07, 2.8381e-07, 2.82177e-07, 2.80558e-07, 2.78953e-07, 2.77362e-07, + 2.75784e-07, 2.74219e-07, 2.72668e-07, 2.7113e-07, 2.69605e-07, 2.68093e-07, 2.66594e-07, 2.65107e-07, 2.63632e-07, 2.6217e-07, 2.60719e-07] +arDeltaAl = [4.66441e-07, 4.63705e-07, 4.60993e-07, 4.58305e-07, 4.55641e-07, 4.53e-07, 4.50382e-07, 4.47786e-07, 4.45213e-07, 4.42661e-07, 4.40132e-07, + 4.37624e-07, 4.35138e-07, 4.32673e-07, 4.30228e-07, 4.27804e-07, 4.254e-07, 4.23018e-07, 4.20654e-07, 4.18311e-07, 4.15987e-07, 4.13683e-07] +#Attenuatio Length tabulated (with constant step) for the photon energy from eStartCRL to eFinCRL +arAttenLenBe = [31.6869, 31.7151, 31.7433, 31.7714, 31.7994, 31.8271, 31.8537, 31.8802, 31.9066, 31.9329, 31.9592, + 31.9853, 32.0114, 32.0375, 32.0634, 32.0893, 32.1151, 32.1408, 32.1665, 32.1921, 32.2176, 32.2421] +arAttenLenAl = [4.48624, 4.51822, 4.54987, 4.58177, 4.61393, 4.64627, 4.67821, 4.71039, 4.74283, 4.77546, 4.80771, + 4.84021, 4.87296, 4.9059, 4.93842, 4.97119, 5.00425, 5.03741, 5.07024, 5.10331, 5.13662, 5.1696] +diamCRL = 1.e-03 #CRL diameter +rMinCRL = 0.2e-03 #CRL radius at the tip of parabola [m] #0.3482e-03 for 15000 eV ? +wallThickCRL = 50e-06 #CRL wall thickness [m] +nCRL_Be = 16 #number of Be lenses +nCRL_Al = 21 #number of Al lenses + +opCRL_Be = srwl_opt_setup_CRL(3, arDeltaBe, arAttenLenBe, 1, diamCRL, diamCRL, rMinCRL, nCRL_Be, wallThickCRL, 0, 0, None, eStartCRL, eFinCRL, 501, 501) +opCRL_Al = srwl_opt_setup_CRL(3, arDeltaAl, arAttenLenAl, 1, diamCRL, diamCRL, rMinCRL, nCRL_Al, wallThickCRL, 0, 0, None, eStartCRL, eFinCRL, 501, 501) + +opPathDifCRL_Be = opCRL_Be.get_data(3, 3, _e = wfrI.mesh.eStart) +auxMeshViewCRL_Be = deepcopy(opCRL_Be.mesh) +auxMeshViewCRL_Be.ne = 1 +auxMeshViewCRL_Be.eStart = wfrI.mesh.eStart +auxMeshViewCRL_Be.eFin = wfrI.mesh.eStart +srwl_uti_save_intens_ascii(opPathDifCRL_Be, auxMeshViewCRL_Be, os.path.join(os.getcwd(), strDataFolderName, strOptPathDifCRL_Be), 0, + ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) +opPathDifCRL_Al = opCRL_Al.get_data(3, 3, _e = wfrI.mesh.eStart) +auxMeshViewCRL_Al = deepcopy(opCRL_Al.mesh) +auxMeshViewCRL_Al.ne = 1 +auxMeshViewCRL_Al.eStart = wfrI.mesh.eStart +auxMeshViewCRL_Al.eFin = wfrI.mesh.eStart +srwl_uti_save_intens_ascii(opPathDifCRL_Al, auxMeshViewCRL_Al, os.path.join(os.getcwd(), strDataFolderName, strOptPathDifCRL_Al), 0, + ['', 'Horizontal Position', 'Vertical Position', 'Opt. Path Diff.'], _arUnits=['', 'm', 'm', 'm']) +print('done') + +opApCRL = SRWLOptA('c', 'a', diamCRL, diamCRL) #CRL Circular Aperture before CRL + +opDriftCRL_Obs = SRWLOptD(9.9519) #Drift space from CRL to ~Waist + +#***********Wavefront Propagation Parameters: +#[0]: Auto-Resize (1) or not (0) Before propagation +#[1]: Auto-Resize (1) or not (0) After propagation +#[2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) +#[3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation +#[4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) +#[5]: Horizontal Range modification factor at Resizing (1. means no modification) +#[6]: Horizontal Resolution modification factor at Resizing +#[7]: Vertical Range modification factor at Resizing +#[8]: Vertical Resolution modification factor at Resizing +#[9]: Type of wavefront Shift before Resizing (not yet implemented) +#[10]: New Horizontal wavefront Center position after Shift (not yet implemented) +#[11]: New Vertical wavefront Center position after Shift (not yet implemented) +# [0] [1] [2] [3] [4] [5] [6] [7] [8] [9][10][11] +ppApCRL = [0., 0., 1., 1, 0, 7.0, 1.0, 3.0, 1.0, 0, 0, 0] +ppCRL_Be = [0, 0, 1., 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] +ppCRL_Al = [0, 0, 1., 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] +ppDriftCRL_Obs = [0, 0, 1., 2, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] +ppFinal = [0, 0, 1., 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0] + +#"Beamline" - Container of Optical Elements (together with the corresponding wavefront propagation instructions) +opBL = SRWLOptC([opApCRL, opCRL_Be, opCRL_Al, opDriftCRL_Obs], + [ppApCRL, ppCRL_Be, ppCRL_Al, ppDriftCRL_Obs])#, ppFinal]) +#sys.exit(0) + +#**********************Calculation (SRWLIB function calls) +#print(srwl_uti_proc_is_master()) + +if(srwl_uti_proc_is_master()): + print(' Performing Spectral Flux (Stokes parameters) vs Photon Energy calculation ... ', end='') + srwl.CalcStokesUR(stkF, eBeam, und, arPrecF) + print('done') + + print(' Performing Electron Trajectory calculation (for test) ... ', end='') + srwl.CalcPartTraj(partTraj, magFldCnt, [1]) + print('done') + + print(' Performing Single-E Electric Field calculation (vs photon energy) ... ', end='') + srwl.CalcElecFieldSR(wfrS, 0, magFldCnt, arPrecS) + print('done') + print(' Extracting Intensity from the Calculated Electric Field ... ', end='') + arIS = array('f', [0]*wfrS.mesh.ne) #array to take intensity data + srwl.CalcIntFromElecField(arIS, wfrS, 6, 0, 0, wfrS.mesh.eStart, 0, 0) + print('done') + + print(' Performing Single-E Electric Field calculation (vs hor. and vert. positions) ... ', end='') + if srcToUse == 'e': + srwl.CalcElecFieldSR(wfrI, 0, magFldCnt, arPrecI) + elif srcToUse == 'g': + srwl.CalcElecFieldGaussian(wfrI, gBeam, arPrecG) + print('done') + print(' Extracting Intensity from the Calculated Electric Field ... ', end='') + auxMeshI0 = deepcopy(wfrI.mesh) + arI = array('f', [0]*auxMeshI0.nx*auxMeshI0.ny) #array to take intensity data + srwl.CalcIntFromElecField(arI, wfrI, 6, 0, 3, auxMeshI0.eStart, 0, 0) + print('done') + + print(' Performing Simulation of Single-E Wavefront Propagation ... ', end='') + startTime = time.time() + srwl.PropagElecField(wfrI, opBL) + print('done (lasted', round((time.time() - startTime)/6.)/10., 'min)') + + print(' Extracting Intensity from the Propagated Electric Field ... ', end='') + auxMeshIP = deepcopy(wfrI.mesh) + arIP = array('f', [0]*auxMeshIP.nx*auxMeshIP.ny) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arIP, wfrI, 6, 0, 3, auxMeshIP.eStart, 0, 0) #extracts intensity + print('done') + + #***********Saving some intermediate results + print(' Saving spectral flux [ph/s/.1%bw], flux per unit surface [ph/s/.1%bw/mm^2], and electron trajectory data to files ... ', end='') + srwl_uti_save_intens_ascii(stkF.arS, stkF.mesh, os.path.join(os.getcwd(), strDataFolderName, strFluxOutFileName)) + partTraj.save_ascii(os.path.join(os.getcwd(), strDataFolderName, strTrjOutFileName)) + srwl_uti_save_intens_ascii(arIS, wfrS.mesh, os.path.join(os.getcwd(), strDataFolderName, strSingleElSpecOutFileName)) + + strI0 = strSingleElIntOutFileName + strIP = strSingleElPropIntOutFileName + if srcToUse == 'g': + strI0 = strSingleGausBeamIntOutFileName + strIP = strSingleGausBeamPropIntOutFileName + srwl_uti_save_intens_ascii(arI, auxMeshI0, os.path.join(os.getcwd(), strDataFolderName, strI0)) + srwl_uti_save_intens_ascii(arIP, auxMeshIP, os.path.join(os.getcwd(), strDataFolderName, strIP)) + print('done') +#sys.exit(0) + +print(' Starting simulation of Partially-Coherent Wavefront Propagation (takes a lot of time)... ') +nMacroElec = 50000 #Total number of Macro-Electrons (Wavefronts) +nMacroElecAvgOneProc = 5 #Number of Macro-Electrons (Wavefronts) to average on each node (for MPI calculations) +nMacroElecSavePer = 5 #Saving periodicity (in terms of Macro-Electrons) for the Resulting Intensity +srCalcMeth = 1 #SR calculation method (1- undulator) +srCalcPrec = 0.01 #SR calculation rel. accuracy + +if srcToUse == 'e': + radStokesProp = srwl_wfr_emit_prop_multi_e(eBeam, magFldCnt, auxMeshP, srCalcMeth, srCalcPrec, nMacroElec, nMacroElecAvgOneProc, nMacroElecSavePer, + os.path.join(os.getcwd(), strDataFolderName, strMultiElPropIntOutFileName), sampFactNxNyForProp, opBL) +elif srcToUse == 'g': + radStokesProp = srwl_wfr_emit_prop_multi_e(eBeam, gBeam, auxMeshP, None, None, nMacroElec, nMacroElecAvgOneProc, nMacroElecSavePer, + os.path.join(os.getcwd(), strDataFolderName, strMultiGausBeamPropIntOutFileName), sampFactNxNyForProp, opBL) +print('done') diff --git a/env/release/srw_python/SRWLIB_Example12.py b/env/release/srw_python/SRWLIB_Example12.py new file mode 100644 index 00000000..2b498cd2 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example12.py @@ -0,0 +1,384 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLIB Example # 12: Simulating Wavefront Propagation through initial part of a Soft X-Ray Undulator Radiation Beamline containing Variable Line Spacing (VLS) Grating +# Based on input and comtributions of N. Canestrari, E. Vescovo, V. Bisogni (BNL) +# v 0.03 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +from uti_plot import * +import os +import sys +import time + +#*********************************Story +help_str='''SRWLIB Python Example # 12: +Simulating emission and propagation of Soft X-ray (250 eV) undulator radiation (UR) wavefront through a beamline containing VLS grating +!!!!!Under development!!!!! +Depending on input options, either single-electron UR wavefront at a fixed photon energy can be calculated and propagated through +the optical scheme, or the calculation of partially-coherent UR from entire electron beam can be started as a loop over "macro-electrons", +using "srwl_wfr_emit_prop_multi_e" function. +This function can run either in "normal" sequential mode, or in parallel mode under "mpi4py". +For this, an MPI2 package and the "mpi4py" Python package have to be installed and configured, and this example has to be started e.g. as: + mpiexec -n 5 python SRWLIB_Example12.py -m 10000 +or with some non-default options as follows: + mpiexec -n 5 python SRWLIB_Example12.py -m 10000 -e 250 -b -0.003 -w 0.00001 +For more information on parallel calculations under "mpi4py" please see documentation to the "mpi4py" and MPI. +Note that the long-lasting partially-coherent UR calculation saves from time to time instant average intensity to an ASCII file, +so the execution of the long loop over "macro-electrons" can be aborted after some time without the danger that all results will be lost. +be sure that a folder data_esm is present in the current working directory. +''' + +#*********************************File Names +strExDataFolderName = 'data_example_12' #example data sub-folder name +strIntSE_OutFilePath = os.path.join(os.getcwd(), strExDataFolderName, 'ex12_res_int_se') #file name for output initial single-electron SR intensity data +strIntPropSE_OutFilePath = os.path.join(os.getcwd(), strExDataFolderName, 'ex12_res_int_prop_se') #file name for output propagated single-electron SR intensity data +strIntPropME_OutFilePath = os.path.join(os.getcwd(), strExDataFolderName, 'ex12_res_int_prop_me') #file name for output propagated multi-electron SR intensity data + +#*********************************Undulator +def setUndulator(_en, _bd=0): + + BbE = { #undulator peak magnetic field by energy + 250. : 0.594024, + 450. : 0.405778, + 1000.: 0.187782, + 1500.: 0.375672, + 2000.: 0.296978 + } + + numPer = 61.5 #Number of ID Periods (without counting for terminations (3.5m, 57mm) + undPer = 0.057 #Period Length [m] + By = BbE[_en]*(1 + _bd) #Peak Vertical field [T] + print('By=', By, 'T') + + phBy = 0 #Initial Phase of the Vertical field component + sBy = 1 #Symmetry of the Vertical field component vs Longitudinal position + xcID = 0 #Transverse Coordinates of Undulator Center [m] + ycID = 0 + zcID = 0 #0 #Longitudinal Coordinate of Undulator Center [m] + + und = SRWLMagFldU([SRWLMagFldH(1, 'v', By, phBy, sBy, 1)], undPer, numPer) #Planar Undulator + mag = SRWLMagFldC([und], array('d', [xcID]), array('d', [ycID]), array('d', [zcID])) #Container of all Field elements + return mag + +#*********************************Electron Beam +def setElecBeam(_dist=0): + ebeam = SRWLPartBeam() + ebeam.Iavg = 0.5 #Average Current [A] + #1st order statistical moments + ebeam.partStatMom1.x = 0. #200e-06 #Initial Transverse Coordinates (initial Longitudinal Coordinate will be defined later on) [m] + ebeam.partStatMom1.y = 0. #-20.e-06 #0. + ebeam.partStatMom1.z = 0. #distance center of straight section to center of the und (which is set to 0) + ebeam.partStatMom1.xp = 0. #Initial Relative Transverse Velocities + ebeam.partStatMom1.yp = 0. + ebeam.partStatMom1.gamma = 3./0.51099890221e-03 #Relative Energy + #2nd order statistical moments + ebeam.arStatMom2[ 0] = (107.086e-06)**2 #<(x-x0)^2> [m^2] + ebeam.arStatMom2[ 1] = 0 #<(x-x0)*(x'-x'0)> [m] + ebeam.arStatMom2[ 2] = (5.13604e-06)**2 #<(x'-x'0)^2> + ebeam.arStatMom2[ 3] = (5.21536e-06)**2 #<(y-y0)^2> [m^2] + ebeam.arStatMom2[ 4] = 0 #<(y-y0)*(y'-y'0)> [m] + ebeam.arStatMom2[ 5] = (1.53393e-06)**2 #<(y'-y'0)^2> + ebeam.arStatMom2[10] = (0.89e-03)**2 #<(E-E0)^2>/E0^2 + if(_dist != 0): ebeam.drift(_dist) + return ebeam + +#*********************************Mesh for Initial Radiation Wavefront calculation +def setRadMesh(_en): + mesh = SRWLRadMesh() + mesh.zStart = 34.366 #Longitudinal Position [m] from Center of Undulator SR has to be calculated + mesh.ne = 1 + mesh.eStart = _en #Initial Photon Energy [eV] + mesh.eFin = mesh.eStart #Final Photon Energy [eV] + hor_ap = 6.76e-03 + ver_ap = 20.e-03 + mesh.nx = 201 + mesh.xStart = -hor_ap*0.5 #-0.00015 #Initial Horizontal Position [m] + mesh.xFin = hor_ap*0.5 # 0.00015 #Final Horizontal Position [m] + mesh.ny = 201 + mesh.yStart = -ver_ap*0.5 #-0.00015 #Initial Vertical Position [m] + mesh.yFin = ver_ap*0.5 # 0.00015 #Final Vertical Position [m] + return mesh + +#*********************************Beamline +def setBeamline(_en, _n_opt_el): + + AbE = { #angle by energy (M2, G_alpha, G_beta) + 250. : (85.3317, 88.4755, 82.1879), + 450. : (86.5319, 88.8813, 84.1826), + 1000.: (87.6789, 89.2577, 86.1001), + 1500.: (88.1060, 89.3957, 86.8163), + 2000.: (88.3603, 89.4775, 87.243) + } + + deg2rad = 3.14159265359/180. + wavelength = 1.239842e-6/_en + #More accurate value seems to be "1.23984193"; however, in C part of SRW "1.239842" is used + + #*****Drift M1 -> M2 + M1_M2 = SRWLOptD(20.434) + + #*****M2 (plane mirror) related + grazM2 = (90.-AbE[_en][0])*deg2rad + tM2, sM2 = 0.430, 0.02 + M2A = SRWLOptA('r', 'a', sM2, tM2*sin(grazM2)) #M2 Aperture + + #*****Drift M2 -> Grating + M2_G = SRWLOptD(0.2) + + #*****Grating (VLS plane) related + vlsG = [1800., 0.08997, 3.004e-6, 9.73e-11] #Polynomial coefficients for VLS Grating Groove Density + grazG = (90.-AbE[_en][1])*deg2rad + + outG = asin(wavelength*vlsG[0]*1.e+03 - cos(grazG)) #Grating Output Angle + defG = grazG + outG + 1.57079632679 #Grating Deflection Angle + + #Grating Input and Output Arms, Tangential and Sagittal Dimensions: + pG, qG, tG, sG = 55., 42.63, 0.200, 0.015 + + qGest = cos(outG)**2/(wavelength*vlsG[1]*1.e+06 - sin(grazG)**2/pG) + + print('Grating Inc. Angle for Central Energy:', AbE[_en][1], 'deg.') + print('Grating Exit Angle:', -outG/deg2rad, 'deg.') + print('Grating Exit Arm (estimated):', qGest, 'm') + + GA = SRWLOptA('r', 'a', sG, tG*sin(grazG)) #Grating Aperture + + #Grating Substrate (plane mirror, deflecting in vertical plane): + GS = SRWLOptMirPl(_size_tang=tG, _size_sag=sG, _ap_shape='r', + _nvx=0, _nvy=cos(grazG), _nvz=-sin(grazG), _tvx=0, _tvy=sin(grazG)) + #The VLS Grating itself: + G = SRWLOptG(_mirSub=GS, _m=1, _grDen=vlsG[0], _grDen1=vlsG[1], _grDen2=vlsG[2], _grDen3=vlsG[3]) + + #*****Drift Grating -> M3 + G_M3 = SRWLOptD(34.63) + + #*****M3 (elliptical horizontally-focusing mirror) related + incM3 = 88.75 + grazM3 = (90.-incM3)*deg2rad + pM3, qM3, tM3, sM3 = 89.63, 8.006, 0.42, 0.02 #M3 Input and Output Arms, Tangential and Sagittal Dimensions + + M3A = SRWLOptA('r', 'a', tM3*sin(grazM3), sM3) #M3 Aperture + + M3 = SRWLOptMirEl(_p=pM3, _q=qM3, _ang_graz=grazM3, _size_tang=tM3, _size_sag=sM3, + _nvx=cos(grazM3), _nvy=0, _nvz=-sin(grazM3), _tvx=-sin(grazM3), _tvy=0) + + #*****Drift M3 -> Secondary Source Aperture (SA) + M3_SA = SRWLOptD(8.006) + + #*****Secondary Source Aperture (i.e. exit aperture of the monochromator) + SA = SRWLOptA('r', 'a', 10.e-03, 10.e-06) #dimensions to check/steer + + #*****M4 (ellipsoid of rotation, horizontally- and vertically-focusing mirror) related + grazM4 = grazM3 + pM4, qM4, tM4, sM4 = 6.01, 0.991, 0.300, 0.050 #M4 Input and Output Arms, Tangential and Sagittal Dimensions + + M4A = SRWLOptA('r', 'a', tM4*sin(grazM4), sM4) #M4 Aperture + + focLenM4 = pM4*qM4/(pM4 + qM4) + rSagM4 = 2*focLenM4*sin(grazM4)*(1. - 0.0032) #to tune... + + #M4 as Ellipsoid of Rotation (under testing!!!) + #M4 = SRWLOptMirEl(_p=pM4, _q=qM4, _ang_graz=grazM4, _r_sag=rSagM4, _size_tang=tM4, _size_sag=sM4, + # _nvx=cos(grazM4), _nvy=0, _nvz=-sin(grazM4), _tvx=-sin(grazM4), _tvy=0) + #M4 as Thin Lens + M4 = SRWLOptL(focLenM4, focLenM4) + + #*****Drift SA -> M4 + SA_M4 = SRWLOptD(pM4) + + #*****Drift M4 -> Sample + M4_S = SRWLOptD(qM4) + + #*****Propagation Parameters for the Optical Elements + #Meaning of the array element below: + #[ 0]: Auto-Resize (1) or not (0) Before propagation + #[ 1]: Auto-Resize (1) or not (0) After propagation + #[ 2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) + #[ 3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation + #[ 4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) + #[ 5]: Horizontal Range modification factor at Resizing (1. means no modification) + #[ 6]: Horizontal Resolution modification factor at Resizing + #[ 7]: Vertical Range modification factor at Resizing + #[ 8]: Vertical Resolution modification factor at Resizing + #[ 9]: Type of wavefront Shift before Resizing (not yet implemented) + #[10]: New Horizontal wavefront Center position after Shift (not yet implemented) + #[11]: New Vertical wavefront Center position after Shift (not yet implemented) + #[12]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Horizontal Coordinate + #[13]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Vertical Coordinate + #[14]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Longitudinal Coordinate + #[15]: Optional: Orientation of the Horizontal Base vector of the Output Frame in the Incident Beam Frame: Horizontal Coordinate + #[16]: Optional: Orientation of the Horizontal Base vector of the Output Frame in the Incident Beam Frame: Vertical Coordinate + + #Some propagation parameters depend on photon energy + # [ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7] [ 8] [ 9] [10] [11] [12] [13] [14] [15] [16] + pM1_M2_db = { + 250. : [ 0, 0, 1.0, 1, 0, 1.2, 6.0, 1.2, 6.0, 0, 0, 0 ], + 450. : [ 0, 0, 1.0, 1, 0, 1.2, 4.0, 1.2, 5.0, 0, 0, 0 ], + 1000.: [ 0, 0, 1.0, 1, 0, 1.2, 3.5, 1.2, 3.0, 0, 0, 0 ], + 1500.: [ 0, 0, 1.0, 1, 0, 1.3, 3.0, 1.2, 3.0, 0, 0, 0 ], + 2000.: [ 0, 0, 1.0, 1, 0, 1.3, 3.0, 1.2, 3.0, 0, 0, 0 ] + } + + pM2A = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pM2_G = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pGA = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pG = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0, 0, sin(defG), cos(defG), 1, 0 ] + pG_M3 = [ 0, 0, 1.0, 2, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] #[3]=2 Ensures manipulation with strict values of Rx, Ry + #pG_M3 = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] #[3]=2 Ensures manipulation with strict values of Rx, Ry + + pM3A = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pM3 = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + + pM3_SA_db = { + 250. : [ 0, 0, 1.0, 4, 0, 1.5, 1.0, 10.0, 1.0, 0, 0, 0 ], #NOTE: reducing resolution may harm... + 450. : [ 0, 0, 1.0, 4, 0, 1.5, 1.0, 10.0, 1.0, 0, 0, 0 ], + 1000.: [ 0, 0, 1.0, 4, 0, 1.0, 1.0, 3.0, 1.0, 0, 0, 0 ], + 1500.: [ 0, 0, 1.0, 4, 0, 1.0, 1.0, 3.0, 1.0, 0, 0, 0 ], + 2000.: [ 0, 0, 1.0, 4, 0, 1.0, 1.0, 3.0, 1.0, 0, 0, 0 ], + } + + pSA_db = { + 250. : [ 0, 0, 1.0, 0, 0, 0.3, 1.0, 0.1, 2.0, 0, 0, 0 ], + 450. : [ 0, 0, 1.0, 0, 0, 0.3, 1.0, 0.1, 2.0, 0, 0, 0 ], + 1000.: [ 0, 0, 1.0, 0, 0, 0.4, 1.0, 0.1, 1.0, 0, 0, 0 ], + 1500.: [ 0, 0, 1.0, 0, 0, 0.4, 1.0, 0.1, 1.0, 0, 0, 0 ], + 2000.: [ 0, 0, 1.0, 0, 0, 0.4, 1.0, 0.1, 1.0, 0, 0, 0 ] + } + + pSA_M4 = [ 0, 0, 1.0, 3, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pM4A = [ 0, 0, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pM4 = [ 0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pM4_S = [ 0, 0, 1.0, 4, 0, 2.0, 1.0, 1.0, 1.0, 0, 0, 0 ] + pSfin = [ 0, 0, 1.0, 1, 1, 1.0, 1.5, 0.3, 2.0, 0, 0, 0 ] + + OE = [ M1_M2, M2A, M2_G, GA, G, G_M3, M3A, M3, M3_SA, SA, SA_M4, M4A, M4, M4_S] + pOE = [ pM1_M2_db[_en], pM2A, pM2_G, pGA, pG, pG_M3, pM3A, pM3, pM3_SA_db[_en], pSA_db[_en], pSA_M4, pM4A, pM4, pM4_S, pSfin] + + #Creating BL "container" (possibly with reduced number of optical elements) + if((_n_opt_el < 0) or (_n_opt_el >= len(pOE))): return SRWLOptC(OE, pOE) + elif(_n_opt_el == 0): return None + else: + OEr = []; pOEr = [] + for i in range(_n_opt_el): + OEr.append(OE[i]); pOEr.append(pOE[i]) + return SRWLOptC(OEr, pOEr) + +#*********************************Single-Electron Emission and Wavefront Propagation calculation +def calcSE(_e_beam, _mag, _mesh, _bl, _sr_meth=1, _sr_prec=0.01, _sr_samp_fact=1, _fnsuf=''): + + #Wavefront (placeholder) + wfr = SRWLWfr() + wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.mesh = deepcopy(_mesh) + wfr.partBeam = deepcopy(_e_beam) + + #Precision Parameters for SR calculation + #_sr_meth: #SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" + #_sr_prec: #relative precision + zStartInteg = 0. #longitudinal position to start integration (effective if < zEndInteg) + zEndInteg = 0. #longitudinal position to finish integration (effective if > zStartInteg) + npTraj = 50000 #Number of points for trajectory calculation + useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) + #_sr_samp_fact: #sampling factor for adjusting nx, ny (effective if > 0) + arPrecPar = [_sr_meth, _sr_prec, zStartInteg, zEndInteg, npTraj, useTermin, _sr_samp_fact] + + sys.stdout.write(' Performing Initial Single-E Electric Field calculation ... '); sys.stdout.flush() + srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecPar) + sys.stdout.write('done\n') + mesh0 = deepcopy(wfr.mesh) + sys.stdout.write(' Extracting Intensity from the Calculated Initial Electric Field ... '); sys.stdout.flush() + arI = array('f', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arI, wfr, 6, 0, 3, mesh0.eStart, 0, 0) + arIx = array('f', [0]*mesh0.nx) #"flat" array to take 1D intensity data + srwl.CalcIntFromElecField(arIx, wfr, 6, 0, 1, mesh0.eStart, 0, 0) + arIy = array('f', [0]*mesh0.ny) #"flat" array to take 1D intensity data + srwl.CalcIntFromElecField(arIy, wfr, 6, 0, 2, mesh0.eStart, 0, 0) + sys.stdout.write('done\n') + sys.stdout.write(' Saving the Initial Wavefront Intensity into a file ... '); sys.stdout.flush() + srwl_uti_save_intens_ascii(arI, mesh0, strIntSE_OutFilePath+_fnsuf) + sys.stdout.write('done\n') + + sys.stdout.write(' Simulating Electric Field Wavefront Propagation ... '); sys.stdout.flush() + t0 = time.time() + srwl.PropagElecField(wfr, _bl) + sys.stdout.write('done\n lasted '+repr(round(time.time() - t0))+' s\n') + mesh1 = deepcopy(wfr.mesh) + sys.stdout.write(' Extracting Intensity from the Propagated Electric Field ... '); sys.stdout.flush() + arI1 = array('f', [0]*mesh1.nx*mesh1.ny) #"flat" 2D array to take intensity data + srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, mesh1.eStart, 0, 0) + #srwl.CalcIntFromElecField(arI1, wfr, 0, 5, 3, mesh1.eStart, 0, 0) #ReEx + #srwl.CalcIntFromElecField(arI1, wfr, 0, 6, 3, mesh1.eStart, 0, 0) #ImEx + arI1x = array('f', [0]*mesh1.nx) #"flat" array to take 1D intensity data + srwl.CalcIntFromElecField(arI1x, wfr, 6, 0, 1, mesh1.eStart, 0, 0) + arI1y = array('f', [0]*mesh1.ny) #"flat" array to take 1D intensity data + srwl.CalcIntFromElecField(arI1y, wfr, 6, 0, 2, mesh1.eStart, 0, 0) + sys.stdout.write('done\n') + sys.stdout.write(' Saving the Propagated Wavefront Intensity data to a file ... '); sys.stdout.flush() + srwl_uti_save_intens_ascii(arI1, mesh1, strIntPropSE_OutFilePath+_fnsuf) + sys.stdout.write('done\n') + + sys.stdout.write(' Plotting the results (blocks script execution; close any graph windows to proceed) ... '); sys.stdout.flush() + plotMesh0x = [1000*mesh0.xStart, 1000*mesh0.xFin, mesh0.nx] + plotMesh0y = [1000*mesh0.yStart, 1000*mesh0.yFin, mesh0.ny] + uti_plot2d(arI, plotMesh0x, plotMesh0y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity Before Propagation']) + uti_plot1d(arIx, plotMesh0x, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity (horizontal cut at y = 0)']) + uti_plot1d(arIy, plotMesh0y, ['Vertical Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity (vertical cut at x = 0)']) + plotMesh1x = [1000*mesh1.xStart, 1000*mesh1.xFin, mesh1.nx] + plotMesh1y = [1000*mesh1.yStart, 1000*mesh1.yFin, mesh1.ny] + uti_plot2d(arI1, plotMesh1x, plotMesh1y, ['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity After Propagation']) + uti_plot1d(arI1x, plotMesh1x, ['Horizontal Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity After Prop. (horizontal cut at y = 0)']) + uti_plot1d(arI1y, plotMesh1y, ['Vertical Position [mm]', 'Intensity [ph/s/.1%bw/mm^2]', 'Intensity After Prop. (vertical cut at x = 0)']) + uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) + sys.stdout.write('all done\n') + +#*********************************Multi-Electron Emission and Wavefront Propagation calculation +def calcME(_e_beam, _mag, _mesh, _bl, _bw=0, _sr_meth=1, _sr_prec=0.01, _sr_samp_fact=1, _n_elec=1000000, _n_avg=10, _n_save_per=10, _fnsuf=''): + + ePhInteg = 0 #Switch to integrate over photon energy or not + + if(_bw > 0): + ePhInteg = 1 + ePhAvg = 0.5*(_mesh.eStart + _mesh.eFin) + rEph = _bw*ePhAvg #0.03 #Range for the Photon Energy integration [eV] + _mesh.eStart = ePhAvg - 0.5*rEph + _mesh.eFin = ePhAvg + 0.5*rEph + _mesh.ne = 1 + + sys.stdout.write(' Starting simulation of Partially-Coherent Wavefront Propagation (takes a lot of time)... ');sys.stdout.flush() + radStokesProp = srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_prec, _n_elec, _n_avg, _n_save_per, + strIntPropME_OutFilePath+_fnsuf, _sr_samp_fact, _bl, _e_ph_integ=ePhInteg) + sys.stdout.write('all done\n') + +#*********************************Entry point +if __name__=="__main__": + import optparse + p = optparse.OptionParser() + p.add_option('-i', '--isamp', dest='isamp', metavar="NUMBER", default=0.07, type="float", help="initial wavefront sampling factor") + p.add_option('-e', '--energy', dest='en', metavar="NUMBER", default=1000, type="float", help="energy [eV]") + p.add_option('-d', '--delta', dest='de', metavar="NUMBER", default=0, type="float", help="delta energy [eV]") + p.add_option('-b', '--bdetune', dest='bd', metavar="NUMBER", default=0, type="float", help="relative detuning of undulator magnetic field from resonant value") + p.add_option('-m', '--melec', dest='melec', metavar="NUMBER", default=1, type="int", help="number of macro-electrons to take into account") + p.add_option('-a', '--melavg', dest='melavg', metavar="NUMBER", default=10, type="int", help="number of mmacro-electrons (wavefronts) to average on each node (for MPI calculations)") + p.add_option('-s', '--melsaveper', dest='melsaveper', metavar="NUMBER", default=10, type="int", help="Saving periodicity (in terms of macro-electrons) of the resulting intensity") + p.add_option('-w', '--bw', dest='bw', metavar="NUMBER", default=0, type="float", help="relative bandwidth (is taken into account at multi-electron calculations)") + p.add_option('-n', '--noptel', dest='noptel', metavar="NUMBER", default=-1, type="int", help="number of optical elements to propagate wavefront through") + p.add_option('-f', '--fnsuf', dest='fnsuf', metavar='FILE', default='', help='output file name suffix') + opt, args = p.parse_args() + + print(help_str) + mag = setUndulator(opt.en, opt.bd) + enPhExact = opt.en + opt.de + mesh = setRadMesh(enPhExact) + e_beam = setElecBeam(-1.9) + beamline = setBeamline(opt.en, opt.noptel) + + fileNameSuf = opt.fnsuf+'_'+repr(enPhExact)+"eV.dat" + + if(opt.melec <= 1): + calcSE(e_beam, mag, mesh, beamline, _sr_samp_fact=opt.isamp, _fnsuf=fileNameSuf) + else: + calcME(e_beam, mag, mesh, beamline, _bw=opt.bw, _sr_samp_fact=opt.isamp, + _n_elec=opt.melec, _n_avg=opt.melavg, _n_save_per=opt.melsaveper, _fnsuf=fileNameSuf) + diff --git a/env/release/srw_python/SRWLIB_Example13.py b/env/release/srw_python/SRWLIB_Example13.py new file mode 100644 index 00000000..e63d81bf --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example13.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLIB Example#13: Simulating emission and propagation of Bending Magnet SR through a simple optical scheme containing one focusing element +# v 0.01 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +from uti_plot import * #required for plotting +import time + +print('SRWLIB Python Example # 13:') +print('Simulating emission and propagation of Bending Magnet Synchrotron Radiaiton wavefront through a simple beamline') + +#***********Data Folder and File Names +strExDataFolderName = 'data_example_13' #example data sub-folder name +strSpecOutFileName0 = 'ex13_res_spec.dat' #file name for output SR spectrum vs photon energy data +strIntOutFileName0 = 'ex13_res_int_se.dat' #file name for output initial single-electron SR intensity vs X and Y data +strIntOutFileName1 = 'ex13_res_int_prop_se.dat' #file name for output propagated single-electron SR intensity vs X and Y data +strIntOutFileName2 = 'ex13_res_int_prop_me.dat' #file name for output propagated multi-electron SR intensity vs X and Y data + +#***********Bending Magnet +B = 0.4 #Dipole magnetic field [T] +LeffBM = 4. #Magnet length [m] (exaggerated, to avoid observinng eventual "edge radiation") +BM = SRWLMagFldM(B, 1, 'n', LeffBM) +magFldCnt = SRWLMagFldC([BM], [0], [0], [0]) #Container of magnetic field elements and their positions in 3D + +#***********Electron Beam +eBeam = SRWLPartBeam() +eBeam.Iavg = 0.5 #Average current [A] +#1st order statistical moments: +eBeam.partStatMom1.x = 0. #Initial horizontal position of central trajectory [m] +eBeam.partStatMom1.y = 0. #Initial vertical position of central trajectory [m] +eBeam.partStatMom1.z = 0. #Initial longitudinal position of central trajectory [m] +eBeam.partStatMom1.xp = 0. #Initial horizontal angle of central trajectory [rad] +eBeam.partStatMom1.yp = 0. #Initial vertical angle of central trajectory [rad] +eBeam.partStatMom1.gamma = 3./0.51099890221e-03 #Relative energy +#2nd order statistical moments: +eBeam.arStatMom2[0] = (127.346e-06)**2 #<(x-x0)^2> [m^2] +eBeam.arStatMom2[1] = -10.85e-09 #<(x-x0)*(x'-x'0)> [m] +eBeam.arStatMom2[2] = (92.3093e-06)**2 #<(x'-x'0)^2> +eBeam.arStatMom2[3] = (13.4164e-06)**2 #<(y-y0)^2> +eBeam.arStatMom2[4] = 0.0072e-09 #<(y-y0)*(y'-y'0)> [m] +eBeam.arStatMom2[5] = (0.8022e-06)**2 #<(y'-y'0)^2> +eBeam.arStatMom2[10] = (0.89e-03)**2 #<(E-E0)^2>/E0^2 + +#***********Radiation Sampling for the On-Axis SR Spectrum +wfrSp = SRWLWfr() #Wavefront structure (placeholder for data to be calculated) +wfrSp.allocate(500, 1, 1) #Numbers of points vs photon energy, horizontal and vertical positions (the last two will be modified in the process of calculation) +wfrSp.mesh.zStart = 5. #Longitudinal position for initial wavefront [m] + +wfrSp.mesh.eStart = 0.1 #Initial photon energy [eV] +wfrSp.mesh.eFin = 10000. #Final photon energy [eV] + +wfrSp.mesh.xStart = 0. #Initial horizontal position [m] +wfrSp.mesh.xFin = wfrSp.mesh.xStart #Final horizontal position [m] +wfrSp.mesh.yStart = 0. #Initial vertical position [m] +wfrSp.mesh.yFin = 0. #Final vertical position [m] + +wfrSp.partBeam = eBeam #e-beam data is contained inside the wavefront struct + +#***********Radiation Sampling for the Initial Wavefront (before first optical element) +wfr = SRWLWfr() #Wavefront structure (placeholder for data to be calculated) +wfr.allocate(1, 10, 10) #Numbers of points vs photon energy, horizontal and vertical positions (the last two will be modified in the process of calculation) + +distSrcLens = 5. #Distance from geometrical source point to lens [m] +wfr.mesh.zStart = distSrcLens #Longitudinal position for initial wavefront [m] + +wfr.mesh.eStart = 0.123984 #Initial photon energy [eV] +#Calculations in this script were tested for photon energies between ~0.0124 and ~0.124 eV (~100 and ~10 microns respectively) +wfr.mesh.eFin = wfr.mesh.eStart #Final photon energy [eV] + +horAng = 0.03 #Horizontal angle [rad] +wfr.mesh.xStart = -0.5*horAng*distSrcLens #Initial horizontal position [m] +wfr.mesh.xFin = 0.5*horAng*distSrcLens #Final horizontal position [m] +verAng = 0.02 #Vertical angle [rad] +wfr.mesh.yStart = -0.5*verAng*distSrcLens #Initial vertical position [m] +wfr.mesh.yFin = 0.5*verAng*distSrcLens #Final vertical position [m] + +wfr.partBeam = eBeam #e-beam data is contained inside the wavefront struct + +#***********Optical Elements and their Corresponding Propagation Parameters +distLensImg = distSrcLens #Distance from lens to image plane +focLen = wfr.mesh.zStart*distLensImg/(distSrcLens + distLensImg) +optLens = SRWLOptL(_Fx=focLen, _Fy=focLen) #Thin lens +optDrift = SRWLOptD(distLensImg) #Drift space from lens to image plane + +#Propagation paramaters (SRW specific) +# [0][1][2] [3][4] [5] [6] [7] [8] +propagParLens = [1, 1, 1., 0, 0, 1., 2., 1., 2., 0, 0, 0] +propagParDrift = [1, 1, 1., 0, 0, 1., 1., 1., 1., 0, 0, 0] +#Wavefront Propagation Parameters: +#[0]: Auto-Resize (1) or not (0) Before propagation +#[1]: Auto-Resize (1) or not (0) After propagation +#[2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) +#[3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation +#[4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) +#[5]: Horizontal Range modification factor at Resizing (1. means no modification) +#[6]: Horizontal Resolution modification factor at Resizing +#[7]: Vertical Range modification factor at Resizing +#[8]: Vertical Resolution modification factor at Resizing +#[9]: Type of wavefront Shift before Resizing (not yet implemented) +#[10]: New Horizontal wavefront Center position after Shift (not yet implemented) +#[11]: New Vertical wavefront Center position after Shift (not yet implemented) + +#"Beamline" - Container of optical elements (together with their corresponding wavefront propagation parameters / instructions) +optBL = SRWLOptC([optLens, optDrift], [propagParLens, propagParDrift]) + +#***********BM SR Calculation +#Precision parameters +meth = 2 #SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" +relPrec = 0.005 #Relative precision +zStartInteg = 0 #Longitudinal position to start integration (effective if < zEndInteg) +zEndInteg = 0 #Longitudinal position to finish integration (effective if > zStartInteg) +npTraj = 20000 #Number of points for trajectory calculation +useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) + +print(' Performing initial SR spectrum calculation ... ', end='') +t0 = time.time() +sampFactNxNyForProp = -1 #Sampling factor for adjusting nx, ny (effective if > 0) +arPrecSR = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] +srwl.CalcElecFieldSR(wfrSp, 0, magFldCnt, arPrecSR) #Calculating electric field +print('done in', round(time.time() - t0), 's') + +print(' Extracting intensity and saving it to a file ... ', end='') +t0 = time.time() +meshSp = deepcopy(wfrSp.mesh) +arSp = array('f', [0]*meshSp.ne) #"Flat" array to take 1D intensity data (vs E) +srwl.CalcIntFromElecField(arSp, wfrSp, 6, 0, 0, meshSp.eStart, 0, 0) #Extracting intensity vs photon energy +srwl_uti_save_intens_ascii(arSp, meshSp, os.path.join(os.getcwd(), strExDataFolderName, strSpecOutFileName0)) +print('done in', round(time.time() - t0), 's') + +print(' Performing initial electric field wavefront calculation ... ', end='') +t0 = time.time() +sampFactNxNyForProp = 0.8 #Sampling factor for adjusting nx, ny (effective if > 0) +arPrecSR = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] +srwl.CalcElecFieldSR(wfr, 0, magFldCnt, arPrecSR) #Calculating electric field +print('done in', round(time.time() - t0), 's') + +print(' Extracting intensity and saving it to a file ... ', end='') +t0 = time.time() +mesh0 = deepcopy(wfr.mesh) +arI0 = array('f', [0]*mesh0.nx*mesh0.ny) #"Flat" array to take 2D intensity data (vs X & Y) +srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, mesh0.eStart, 0, 0) #Extracting intensity vs horizontal and vertical positions +srwl_uti_save_intens_ascii(arI0, mesh0, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName0)) +print('done in', round(time.time() - t0), 's') + +#***********Wavefront Propagation +print(' Simulating single-electron electric field wavefront propagation ... ', end='') +t0 = time.time() +srwl.PropagElecField(wfr, optBL) +print('done in', round(time.time() - t0), 's') + +print(' Extracting intensity from calculated electric field and saving it to file(s) ... ', end='') +t0 = time.time() +mesh1 = deepcopy(wfr.mesh) +arI1s = array('f', [0]*mesh1.nx*mesh1.ny) #"Flat" array to take 2D single-electron intensity data (vs X & Y) +srwl.CalcIntFromElecField(arI1s, wfr, 6, 0, 3, mesh1.eStart, 0, 0) #Extracting single-electron intensity vs X & Y +srwl_uti_save_intens_ascii(arI1s, mesh1, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName1)) + +arI1m = deepcopy(arI1s) #"Flat" array to take 2D multi-electron intensity data (vs X & Y) +srwl.CalcIntFromElecField(arI1m, wfr, 6, 1, 3, mesh1.eStart, 0, 0) #Calculating multi-electron intensity vs X & Y using convolution method (assuming it to be valid!) +srwl_uti_save_intens_ascii(arI1m, mesh1, os.path.join(os.getcwd(), strExDataFolderName, strIntOutFileName2)) + +print('done in', round(time.time() - t0), 's') + +#***********Plotting the Calculation Results +uti_plot1d(arSp, [meshSp.eStart, meshSp.eFin, meshSp.ne], labels=('Photon Energy', 'Spectral Intensity', 'On-Axis SR Intensity Spectrum'), units=['eV', 'ph/s/0.1%bw/mm^2']) +unitsIntPlot = ['m', 'm', 'ph/s/.1%bw/mm^2'] +uti_plot2d1d(arI0, [mesh0.xStart, mesh0.xFin, mesh0.nx], [mesh0.yStart, mesh0.yFin, mesh0.ny], labels=('Horizontal position', 'Vertical position', 'Intensity Before Lens'), units=unitsIntPlot) +uti_plot2d1d(arI1s, [mesh1.xStart, mesh1.xFin, mesh1.nx], [mesh1.yStart, mesh1.yFin, mesh1.ny], labels=('Horizontal position', 'Vertical position', 'Single-E Intensity in Image Plane'), units=unitsIntPlot) +uti_plot2d1d(arI1m, [mesh1.xStart, mesh1.xFin, mesh1.nx], [mesh1.yStart, mesh1.yFin, mesh1.ny], labels=('Horizontal position', 'Vertical position', 'Multi-E Intensity in Image Plane'), units=unitsIntPlot) +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) diff --git a/env/release/srw_python/SRWLIB_Example14.py b/env/release/srw_python/SRWLIB_Example14.py new file mode 100644 index 00000000..fd6476e5 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example14.py @@ -0,0 +1,420 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLIB Example#14: Simulating propagation of a Gaussian X-ray beam through a simple optical scheme +# containing C(400) dual-crystal monochromator +# v 0.01 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +from uti_math import * +from uti_plot import * #required for plotting +import os +import time + +print('SRWLIB Python Example # 14:') +print('!!!!!Under testing!!!!!') +print('Simulating propagation of a Gaussian X-ray beam through a simple optical scheme containing C(400) dual-crystal monochromator') + +#**********************Auxiliary Functions +def ExtractAndSavePulseData(_wfr, _fn_prefix, _ec=0, _xc=0, _yc=0): + """Extract and save to file radiation pulse characteristics""" + + arIIvsT = None; arIvsT = None; arFvsXY = None; arIvsXY = None; #arPhvsXY = None; arIvsX = None; arIvsY = None + meshIvsT = None; meshIvsXY = None + + sFirstDep = 'Photon Energy' + sFirstDepUnit = 'eV' + sResCharI = 'Spectral Energy' + sResChar = 'Spectral Fluence' + sResUnit = 'J/eV' + sEorT = 'e' + if(_wfr.presFT == 1): #Time domain + sFirstDep = 'Time' + sFirstDepUnit = 's' + sResCharI = 'Power' + sResChar = 'Power Density' + sResUnit = 'W' + sEorT = 't' + suf = '_' + sEorT + + mesh0 = _wfr.mesh + if(mesh0.ne > 1): + + #Vs Photon Energy or Time, Integrated over X&Y + arIIvsT = array('f', [0]*mesh0.ne) #array to take 1D data + srwl.CalcIntFromElecField(arIIvsT, _wfr, 6, 2, 0, _ec, _xc, _yc) #extracts power vs t or spec. energy vs e + meshIvsT = deepcopy(mesh0) + meshIvsT.nx = 1; meshIvsT.xStart = _xc; meshIvsT.xFin = _xc + meshIvsT.ny = 1; meshIvsT.yStart = _yc; meshIvsT.yFin = _yc + srwl_uti_save_intens_ascii(arIIvsT, meshIvsT, _fn_prefix + suf + 'i' + suf + '.dat', + _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', sResCharI], + _arUnits=[sFirstDepUnit, 'm', 'm', sResUnit]) + #Vs Photon Energy or Time, Cut + arIvsT = array('f', [0]*mesh0.ne) #array to take 1D data + srwl.CalcIntFromElecField(arIvsT, _wfr, 6, 0, 0, _ec, _xc, _yc) #extracts power density vs t or spec. fluence vs e + #srwl.CalcIntFromElecField(arIvsT, _wfr, 0, 5, 0, _ec, _xc, _yc) #extracts Re(Ex) vs t or vs e + #srwl.CalcIntFromElecField(arIvsT, _wfr, 0, 6, 0, _ec, _xc, _yc) #extracts Im(Ex) vs t or vs e + + srwl_uti_save_intens_ascii(arIvsT, meshIvsT, _fn_prefix + suf + suf + '.dat', + _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', sResChar], + _arUnits=[sFirstDepUnit, 'm', 'm', sResUnit + '/mm^2']) + if(_wfr.presFT == 0): + #Fluence vs X&Y (calculate it only in Frequency domain, because it is the same in both domains) + arFvsXY = array('f', [0]*mesh0.nx*mesh0.ny) #array to take 2D data + srwl.CalcIntFromElecField(arFvsXY, _wfr, 6, 7, 3, _ec, _xc, _yc) + meshIvsXY = deepcopy(mesh0) + meshIvsXY.ne = 1; meshIvsXY.eStart = _ec; meshIvsXY.eFin = _ec + srwl_uti_save_intens_ascii(arFvsXY, meshIvsXY, _fn_prefix + '_fluence_xy.dat', + _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', 'Fluence'], + _arUnits=[sFirstDepUnit, 'm', 'm', 'J/mm^2']) + #Vs X&Y + arIvsXY = array('f', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D data + srwl.CalcIntFromElecField(arIvsXY, _wfr, 6, 0, 3, _ec, _xc, _yc) #extracts intensity + #srwl.CalcIntFromElecField(arIvsXY, _wfr, 0, 5, 3, _ec, _xc, _yc) #extracts Re(Ex) + #srwl.CalcIntFromElecField(arIvsXY, _wfr, 0, 6, 3, _ec, _xc, _yc) #extracts Im(Ex) + + if(meshIvsXY == None): + meshIvsXY = deepcopy(mesh0) + meshIvsXY.ne = 1; meshIvsXY.eStart = _ec; meshIvsXY.eFin = _ec + srwl_uti_save_intens_ascii(arIvsXY, meshIvsXY, _fn_prefix + suf + '_xy.dat', + _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', sResChar], + _arUnits=[sFirstDepUnit, 'm', 'm', sResUnit + '/mm^2']) + #Phase vs X&Y + #arPhvsXY = array('d', [0]*mesh0.nx*mesh0.ny) #"flat" array to take 2D phase data (note it should be 'd') + #srwl.CalcIntFromElecField(arPhvsXY, _wfr, 0, 4, 3, _ec, _xc, _yc) #extracts radiation phase + #srwl_uti_save_intens_ascii(arPhvsXY, meshIvsXY, _fn_prefix + suf + '_ph_xy.dat', + # _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', 'Phase'], + # _arUnits=[sFirstDepUnit, 'm', 'm', 'rad']) + #Vs X + #arIvsX = array('f', [0]*mesh0.nx) #array to take 1D data + #srwl.CalcIntFromElecField(arIvsX, _wfr, 6, 0, 1, _ec, _xc, _yc) #extracts power density or spec. fluence vs x + #meshIvsX = deepcopy(mesh0) + #meshIvsX.ne = 1; meshIvsX.eStart = _ec; meshIvsX.eFin = _ec + #meshIvsX.ny = 1; meshIvsX.yStart = _yc; meshIvsX.yFin = _yc + #srwl_uti_save_intens_ascii(arIvsX, meshIvsX, _fn_prefix + suf + '_x.dat', + # _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', sResChar], + # _arUnits=[sFirstDepUnit, 'm', 'm', sResUnit + '/mm^2']) + #Vs Y + #arIvsY = array('f', [0]*mesh0.ny) #array to take 1D data + #srwl.CalcIntFromElecField(arIvsY, _wfr, 6, 0, 2, _ec, _xc, _yc) #extracts power density or spec. fluence vs y + #meshIvsY = deepcopy(mesh0) + #meshIvsY.ne = 1; meshIvsY.eStart = _ec; meshIvsY.eFin = _ec + #meshIvsY.nx = 1; meshIvsY.xStart = _xc; meshIvsY.xFin = _xc + #srwl_uti_save_intens_ascii(arIvsY, meshIvsY, os.path.join(os.getcwd(), _fn_prefix + suf + '_y.dat'), + # _arLabels=[sFirstDep, 'Horizontal Position', 'Vertical Position', sResChar], + # _arUnits=[sFirstDepUnit, 'm', 'm', sResUnit + '/mm^2']) + + return [[arIIvsT, arIvsT, arFvsXY, arIvsXY], [meshIvsT, meshIvsXY]] + +#**********************Input Parameters and Structures +#***********Folder and Data File Names +strDataFolderName = 'data_example_14' #data sub-folder name +strIntOutFileNameCore0 = 'ex14_res_int_in' #file name core for initial radiation intensity data +strPhOutFileNameCore0 = 'ex14_res_ph_in' #file name core for initial radiation phase data +strIntOutFileNameCore1 = 'ex14_res_int_pr' #file name core for propagated radiation intensity data +strPhOutFileNameCore1 = 'ex14_res_ph_pr' #file name core for propagated radiation phase data + +#***********Gaussian Beam structure +GsnBm = SRWLGsnBm() +GsnBm.x = 0 #Transverse Positions of Gaussian Beam Center at Waist [m] +GsnBm.y = 0 +GsnBm.z = 0 #Longitudinal Position of Waist [m] +GsnBm.xp = 0 #Average Angles of Gaussian Beam at Waist [rad] +GsnBm.yp = 0 +GsnBm.avgPhotEn = 8230 #Photon Energy [eV] +GsnBm.pulseEn = 0.001 #Pulse Energy [J] - to be corrected +GsnBm.repRate = 1 #Rep. Rate [Hz] - to be corrected +GsnBm.polar = 1 #1- linear hoirizontal + +#lambMdivFourPi = (1.23984186e-06/(4*3.1415926536))/GsnBm.avgPhotEn +constConvRad = 1.23984186e-06/(4*3.1415926536) +rmsAngDivAt8keV = 3.e-06 #1.e-06 #RMS divergence [rad] at 8 keV + +GsnBm.sigX = constConvRad/(8000*rmsAngDivAt8keV) #Horiz. RMS size at Waist [m] +#print('RMS Source Size [m]:', GsnBm.sigX) +GsnBm.sigY = GsnBm.sigX #Vert. RMS size at Waist [m] +rmsAngDiv = constConvRad/(GsnBm.avgPhotEn*GsnBm.sigX) #RMS angular divergence [rad] +GsnBm.sigT = 10.e-15 #Pulse duration [s] (not used?) +GsnBm.mx = 0 #Transverse Gauss-Hermite Mode Orders +GsnBm.my = 0 + +#***********Wavefront structure +wfr = SRWLWfr() + +doTimeDependent = False #Make True to do time-dependent calculation + +if(doTimeDependent): +#Use this for Time-Dependent calculations: + wfr.allocate(50, 100, 100) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.presFT = 1 #presentation/domain: 0- frequency (photon energy), 1- time + wfr.mesh.eStart = -5.*GsnBm.sigT #Initial Time [s] + wfr.mesh.eFin = 5.*GsnBm.sigT #Final Time [s] +else: +#Use this for Steady-State calculations: + wfr.allocate(1, 100, 100) #Numbers of points vs Photon Energy (1), Horizontal and Vertical Positions (dummy) + wfr.presFT = 0 #Presentation/domain: 0- frequency (photon energy), 1- time + wfr.mesh.eStart = GsnBm.avgPhotEn #Initial Photon Energy [eV] + wfr.mesh.eFin = GsnBm.avgPhotEn #Final Photon Energy [eV] + +wfr.mesh.zStart = 200 #Longitudinal Position [m] at which the initial Electric Field has to be calculated, i.e. the position of the first optical element +distSrc_Opt = wfr.mesh.zStart - GsnBm.z #Distance bw Source (waist) and first optical element (center) + +horAp = 8*rmsAngDiv*distSrc_Opt #First Aperture size / "window" for simulations [m] +wfr.mesh.xStart = -0.5*horAp #Initial Horizontal Position [m] +wfr.mesh.xFin = 0.5*horAp #Final Horizontal Position [m] +vertAp = horAp +wfr.mesh.yStart = -0.5*vertAp #Initial Vertical Position [m] +wfr.mesh.yFin = 0.5*vertAp #Final Vertical Position [m] + +wfr.avgPhotEn = GsnBm.avgPhotEn +wfr.unitElFld = 2 #Electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) + +wfr.partBeam.partStatMom1.x = GsnBm.x #Some information about the source in the Wavefront structure +wfr.partBeam.partStatMom1.y = GsnBm.y +wfr.partBeam.partStatMom1.z = GsnBm.z +wfr.partBeam.partStatMom1.xp = GsnBm.xp +wfr.partBeam.partStatMom1.yp = GsnBm.yp + +sampFactNxNyForProp = 0.5 #1.1 #Sampling factor for adjusting nx, ny in the initial wavefront (effective if > 0) + +#***********Optical Elements and Propagation Parameters +#Sequence of Optical Elements: +# <1st Crystal of DCM> +# <2nd Crystal of DCM> +# + +#C(400) Crystal Constants: +dSpC400 = 0.89178 #Crystal reflecting planes d-spacing for C(400) crystal +#psi0rC400 = -0.17530e-04; psi0iC400 = 0.21089e-07 #Real and imaginary parts of 0-th Fourier component of crystal polarizability +psi0rC400 = -0.21732e-04; psi0iC400 = 0.28005e-07 #Real and imaginary parts of 0-th Fourier component of crystal polarizability +#psihrC400 = -0.45300e-05; psihiC400 = 0.20314E-07 #Real and imaginary parts of h-th Fourier component of crystal polarizability +psihrC400 = -0.54377e-05; psihiC400 = 0.25934E-07 #Real and imaginary parts of h-th Fourier component of crystal polarizability +psihbrC400 = psihrC400; psihbiC400 = psihiC400 #Real and imaginary parts of -h-th Fourier component of crystal polarizability +thickCryst = 10.e-03 #0.5e-03 #Thickness of each crystal [m] +angAsCryst = 0 #Asymmetry angle of each crystal [rad] + +#1st Crystal: +opCr1 = SRWLOptCryst(_d_sp=dSpC400, _psi0r=psi0rC400, + _psi0i=psi0iC400, _psi_hr=psihrC400, _psi_hi=psihiC400, _psi_hbr=psihbrC400, _psi_hbi=psihbiC400, + _tc=thickCryst, _ang_as=angAsCryst) +#Find appropriate orientation of the 1st crystal and the corresponding output beam frame (in the incident beam frame): +orientDataCr1 = opCr1.find_orient(GsnBm.avgPhotEn) +orientCr1 = orientDataCr1[0] #1st crystal orientation +tCr1 = orientCr1[0]; nCr1 = orientCr1[2] # Tangential and Normal vectors to crystal surface +print(' 1st crystal orientation:'); print(' t=', tCr1, 's=', orientCr1[1], 'n=', nCr1) +#Set crystal orientation: +opCr1.set_orient(nCr1[0], nCr1[1], nCr1[2], tCr1[0], tCr1[1]) +orientOutFrCr1 = orientDataCr1[1] #Orientation (coordinates of base vectors) of the output beam frame +rxCr1 = orientOutFrCr1[0]; ryCr1 = orientOutFrCr1[1]; rzCr1 = orientOutFrCr1[2] #Horizontal, Vertical and Longitudinal base vectors of the output beam frame +print(' 1st crystal output beam frame:'); print(' ex=', rxCr1, 'ey=', ryCr1, 'ez=', rzCr1) +TrM = [rxCr1, ryCr1, rzCr1] #Input/Output beam transformation matrix (for debugging) +print(' Beam frame transformation matrix (from the begining of opt. scheme to output of current element):') +uti_math.matr_print(TrM) + +#2nd Crystal: +opCr2 = SRWLOptCryst(_d_sp=dSpC400, _psi0r=psi0rC400, + _psi0i=psi0iC400, _psi_hr=psihrC400, _psi_hi=psihiC400, _psi_hbr=psihbrC400, _psi_hbi=psihbiC400, + _tc=thickCryst, _ang_as=angAsCryst) +#Find appropriate orientation of the 2nd crystal and the corresponding output beam frame (in the incident beam frame): +orientDataCr2 = opCr2.find_orient(GsnBm.avgPhotEn, _ang_dif_pl=3.141593) +orientCr2 = orientDataCr2[0] #2nd crystal orientation +tCr2 = orientCr2[0]; nCr2 = orientCr2[2] # Tangential and Normal vectors to crystal surface +print(' 2nd crystal orientation:'); print(' t=', tCr2, 's=', orientCr2[1], 'n=', nCr2) +#Set crystal orientation: +opCr2.set_orient(nCr2[0], nCr2[1], nCr2[2], tCr2[0], tCr2[1]) +orientOutFrCr2 = orientDataCr2[1] #Orientation (coordinates of base vectors) of the output beam frame +rxCr2 = orientOutFrCr2[0]; ryCr2 = orientOutFrCr2[1]; rzCr2 = orientOutFrCr2[2] #Horizontal, Vertical and Longitudinal base vectors of the output beam frame +print(' 2nd crystal output beam frame:'); print(' ex=', rxCr2, 'ey=', ryCr2, 'ez=', rzCr2) +TrM = uti_math.matr_prod(TrM, [rxCr2, ryCr2, rzCr2]) #Input/Output beam transformation matrix (for debugging) +print(' Beam frame transformation matrix (from the begining of opt. scheme to output of current element):') +uti_math.matr_print(TrM) +print(' After the two crystals of DCM, the transformation matrix should be close to the unit matrix.') + +#Drift after DCM: +opDCM_Samp = SRWLOptD(20.) + +#Wavefront Propagation Parameters: +#[0]: Auto-Resize (1) or not (0) Before propagation +#[1]: Auto-Resize (1) or not (0) After propagation +#[2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) +#[3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation +#[4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) +#[5]: Horizontal Range modification factor at Resizing (1. means no modification) +#[6]: Horizontal Resolution modification factor at Resizing +#[7]: Vertical Range modification factor at Resizing +#[8]: Vertical Resolution modification factor at Resizing +#[9]: Type of wavefront Shift before Resizing (not yet implemented) +#[10]: New Horizontal wavefront Center position after Shift (not yet implemented) +#[11]: New Vertical wavefront Center position after Shift (not yet implemented) +# [0][1][2] [3][4] [5] [6] [7] [8] [9][10][11] +prParInit = [0, 0, 1., 1, 0, 1., 2., 1.3, 2., 0, 0, 0] +prPar0 = [0, 0, 1., 1, 0, 1., 1., 1., 1., 0, 0, 0] +prParPost = [0, 0, 1., 0, 0, 1., 0.25, 1., 0.25, 0, 0, 0] +#NOTE: in this case of simulation, it can be enough to define the precision parameters only Before and After +#the propagation through the entire Beamline. However, if necessary, different propagation parameters can be specified +#for each optical element. +#The optimal values of propagation parameters may depend on photon energy and optical layout. + +#"Beamline" - a sequenced Container of Optical Elements (together with the corresponding wavefront propagation parameters, +#and the "post-propagation" wavefront resizing parameters for better viewing): +optBL = SRWLOptC([opCr1, opCr2, opDCM_Samp], + [prParInit, prPar0, prPar0, prParPost]) + +#**********************Calculation +#***********Initial Gaussian Beam Wavefront +print('Calculating initial wavefront...', end='') +t0 = time.time() +srwl.CalcElecFieldGaussian(wfr, GsnBm, [sampFactNxNyForProp]) +print('done in', round(time.time() - t0), 's') + +arPI0vsT = None; arP0vsT = None; arP0vsXY = None; #arP0vsX = None; arP0vsY = None +meshP0vsT = None; meshP0vsXY = None; #meshP0vsX = None; meshP0vsY = None +tc0 = 0 #Time moment for power density cut [s] +if((wfr.mesh.ne > 1) and (wfr.presFT == 1)): + + print('Extracting initial power (density) in time domain and saving to files...', end='') + t0 = time.time() + [[arPI0vsT, arP0vsT, arF0vsXYdummy, arP0vsXY], [meshP0vsT, meshP0vsXY]] = ExtractAndSavePulseData(wfr, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileNameCore0), _ec=tc0) + print('done in', round(time.time() - t0), 's') + + print('Resizing: increasing time range to improve resolution in frequency domain...', end='') + t0 = time.time() + srwl.ResizeElecField(wfr, 'f', [0, 35., 0.7]) + print('done in', round(time.time() - t0), 's') + + print('Switching from time to frequency domain...', end='') + t0 = time.time() + srwl.SetRepresElecField(wfr, 'f') + print('done in', round(time.time() - t0), 's') + + print('Resizing: decreasing photon energy range to speed-up calculation and save memory...', end='') + t0 = time.time() + srwl.ResizeElecField(wfr, 'f', [0, 0.12, 1.]) + print('done in', round(time.time() - t0), 's') + +ec0 = wfr.avgPhotEn #Photon energy for spectral fluence cut [eV] + +print('Extracting initial spectral fluence in frequency domain and saving it to files...', end='') +t0 = time.time() +[[arII0vsE, arI0vsE, arF0vsXY, arI0vsXY], [meshI0vsE, meshI0vsXY]] = ExtractAndSavePulseData(wfr, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileNameCore0), _ec=ec0) +print('done in', round(time.time() - t0), 's') + +#***********Wavefront Propagation +if(wfr.mesh.ne > 1): + print('Starting propagation of time/frequency-dependent radiation pulse (may take many munites)') +else: + print('Starting propagation of monochromatic wavefront') +print('Propagating wavefront...', end='') +t0 = time.time() +srwl.PropagElecField(wfr, optBL) +print('done in', round(time.time() - t0), 's') + +ec1 = wfr.avgPhotEn #Photon energy for spectral fluence cut [eV] + +print('Extracting propagated spectral fluence in frequency domain and saving it to files...', end='') +t0 = time.time() +[[arII1vsE, arI1vsE, arF1vsXY, arI1vsXY], [meshI1vsE, meshI1vsXY]] = ExtractAndSavePulseData(wfr, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileNameCore1), _ec=ec1) +print('done in', round(time.time() - t0), 's') + +arPI1vsT = None; arP1vsT = None; arP1vsXY = None +meshP1vsT = None; meshP1vsXY = None +tc1 = 40e-15 #-40e-15 #Time moment for power density cut [s] +if(wfr.mesh.ne > 1): + print('Resizing: increasing photon energy range to increase resolution in time domain...', end='') + t0 = time.time() + srwl.ResizeElecField(wfr, 'f', [0, 3., 1.]) + print('done in', round(time.time() - t0), 's') + + print('Switching from frequency to time domain...', end='') + t0 = time.time() + srwl.SetRepresElecField(wfr, 't') + print('done in', round(time.time() - t0), 's') + + print('Resizing: decreasing time range to reduce amount of output data...', end='') + t0 = time.time() + srwl.ResizeElecField(wfr, 'f', [0, 0.2, 1.]) + print('done in', round(time.time() - t0), 's') + + print('Extracting propagated power (density) in time domain and saving it to files...', end='') + t0 = time.time() + [[arPI1vsT, arP1vsT, arF1vsXYdummy, arP1vsXY], [meshP1vsT, meshP1vsXY]] = ExtractAndSavePulseData(wfr, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileNameCore1), _ec=tc1) + print('done in', round(time.time() - t0), 's') + + #TEST + #print('Switching from Time to Frequency domain (for test)...', end='') + #t0 = time.time() + #srwl.SetRepresElecField(wfr, 'f') + #print('done in', round(time.time() - t0), 's') + +#TEST +#print('Extracting propagated spectral fluence in frequency domain and saving it to files (for test)...', end='') +#t0 = time.time() +#[[arII2vsE, arI2vsE, arF2vsXY, arI2vsXY], [meshI2vsE, meshI2vsXY]] = ExtractAndSavePulseData(wfr, os.path.join(os.getcwd(), strDataFolderName, strIntOutFileNameCore1), _ec=ec1) +#print('done in', round(time.time() - t0), 's') + +#sys.exit() + +#**********************Plotting results (requires 3rd party graphics package) +print(' Plotting the results (blocks script execution; close all graph windows to proceed) ... ', end='') + +#Pulse Characteristics BEFORE Propagation +if(meshP0vsT != None): + plotMeshP0vsT = [meshP0vsT.eStart, meshP0vsT.eFin, meshP0vsT.ne] + uti_plot1d(arPI0vsT, plotMeshP0vsT, ['Time [s]', 'Power [W]', 'Power Before Propagation']) + uti_plot1d(arP0vsT, plotMeshP0vsT, ['Time [s]', 'Power Density [W/mm^2]', 'On-Axis Power Density Before Propagation']) + +if(meshP0vsXY != None): + plotMeshP0vsX = [meshP0vsXY.xStart, meshP0vsXY.xFin, meshP0vsXY.nx] + plotMeshP0vsY = [meshP0vsXY.yStart, meshP0vsXY.yFin, meshP0vsXY.ny] + uti_plot2d1d(arP0vsXY, plotMeshP0vsX, plotMeshP0vsY, x=0, y=0, labels=['Horizontal Position', 'Vertical Position', 'Power Density Before Propagation at t=' + repr(round(tc0*1.e+15)) + ' fs'], units=['m', 'm', 'W/mm^2']) + +if(meshI0vsE != None): + plotMeshI0vsE = [meshI0vsE.eStart, meshI0vsE.eFin, meshI0vsE.ne] + uti_plot1d(arII0vsE, plotMeshI0vsE, ['Photon Energy [eV]', 'Spectral Emergy [J/eV]', 'Spectral Energy Before Propagation']) + uti_plot1d(arI0vsE, plotMeshI0vsE, ['Photon Energy [eV]', 'Spectral Fluence [J/eV/mm^2]', 'On-Axis Spectral Fluence Before Propagation']) + +plotMeshI0vsX = [meshI0vsXY.xStart, meshI0vsXY.xFin, meshI0vsXY.nx] +plotMeshI0vsY = [meshI0vsXY.yStart, meshI0vsXY.yFin, meshI0vsXY.ny] +uti_plot2d1d(arI0vsXY, plotMeshI0vsX, plotMeshI0vsY, labels=['Horizontal Position', 'Vertical Position', 'Spectral Fluence Before Propagation at E=' + repr(round(ec0)) + ' eV'], units=['m', 'm', 'J/eV/mm^2']) + +if(arF0vsXY != None): + uti_plot2d1d(arF0vsXY, plotMeshI0vsX, plotMeshI0vsY, x=0, y=0, labels=['Horizontal Position', 'Vertical Position', 'Fluence Before Propagation'], units=['m', 'm', 'J/mm^2']) + +#Pulse Characteristics AFTER Propagation +if(meshI1vsE != None): + plotMeshI1vsE = [meshI1vsE.eStart, meshI1vsE.eFin, meshI1vsE.ne] + uti_plot1d(arII1vsE, plotMeshI1vsE, ['Photon Energy [eV]', 'Spectral Emergy [J/eV]', 'Spectral Energy After Propagation']) + uti_plot1d(arI1vsE, plotMeshI1vsE, ['Photon Energy [eV]', 'Spectral Fluence [J/eV/mm^2]', 'On-Axis Spectral Fluence After Propagation']) + +plotMeshI1vsX = [meshI1vsXY.xStart, meshI1vsXY.xFin, meshI1vsXY.nx] +plotMeshI1vsY = [meshI1vsXY.yStart, meshI1vsXY.yFin, meshI1vsXY.ny] +uti_plot2d1d(arI1vsXY, plotMeshI1vsX, plotMeshI1vsY, labels=['Horizontal Position', 'Vertical Position', 'Spectral Fluence After Propagation at E=' + repr(round(ec1)) + ' eV'], units=['m', 'm', 'J/eV/mm^2']) + +if(arF1vsXY != None): + uti_plot2d1d(arF1vsXY, plotMeshI1vsX, plotMeshI1vsY, x=0, y=0, labels=['Horizontal Position', 'Vertical Position', 'Fluence After Propagation'], units=['m', 'm', 'J/mm^2']) + +if(meshP1vsT != None): + plotMeshP1vsT = [meshP1vsT.eStart, meshP1vsT.eFin, meshP1vsT.ne] + uti_plot1d(arPI1vsT, plotMeshP1vsT, ['Time [s]', 'Power [W]', 'Power After Propagation']) + uti_plot1d(arP1vsT, plotMeshP1vsT, ['Time [s]', 'Power Density [W/mm^2]', 'On-Axis Power Density After Propagation']) + +if(meshP1vsXY != None): + plotMeshP1vsX = [meshP1vsXY.xStart, meshP1vsXY.xFin, meshP1vsXY.nx] + plotMeshP1vsY = [meshP1vsXY.yStart, meshP1vsXY.yFin, meshP1vsXY.ny] + uti_plot2d1d(arP1vsXY, plotMeshP1vsX, plotMeshP1vsY, x=0, y=0, labels=['Horizontal Position', 'Vertical Position', 'Power Density After Propagation at t= ' + repr(round(tc1*1.e+15)) + ' fs'], units=['m', 'm', 'W/mm^2']) + +#TEST +#plotMeshI2vsE = [meshI2vsE.eStart, meshI2vsE.eFin, meshI2vsE.ne] +#uti_plot1d(arII2vsE, plotMeshI2vsE, ['Photon Energy [eV]', 'Spectral Emergy [J/eV]', 'Spectral Energy After Propagation (test)']) +#uti_plot1d(arI2vsE, plotMeshI2vsE, ['Photon Energy [eV]', 'Spectral Fluence [J/eV/mm^2]', 'On-Axis Spectral Fluence After Propagation (test)']) + +#plotMeshI2vsX = [meshI2vsXY.xStart, meshI2vsXY.xFin, meshI2vsXY.nx] +#plotMeshI2vsY = [meshI2vsXY.yStart, meshI2vsXY.yFin, meshI2vsXY.ny] +#uti_plot2d1d(arI2vsXY, plotMeshI2vsX, plotMeshI2vsY, labels=['Horizontal Position', 'Vertical Position', 'Spectral Fluence After Propagation (test)'], units=['m', 'm', 'J/eV/mm^2']) + +#if(arF2vsXY != None): +# uti_plot2d1d(arF2vsXY, plotMeshI2vsX, plotMeshI2vsY, x=0, y=0, labels=['Horizontal Position', 'Vertical Position', 'Fluence After Propagation (test)'], units=['m', 'm', 'J/mm^2']) + +uti_plot_show() #show all graphs (blocks script execution; close all graph windows to proceed) +print('done') diff --git a/env/release/srw_python/SRWLIB_Example15.py b/env/release/srw_python/SRWLIB_Example15.py new file mode 100644 index 00000000..b27f3679 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example15.py @@ -0,0 +1,257 @@ +# -*- coding: utf-8 -*- + +""" +The example was created by Timur Shaftan (BNL) for RadTrack project (https://github.com/radiasoft/radtrack). +Adapted by Maksim Rakitin (BNL). +The purpose of the example is to demonstrate good agreement of the SRW simulation +of propagation of a gaussian beam through a drift with an analytical estimation. +""" +# v. 0.03 + +from __future__ import print_function +import uti_plot +from srwlib import * +from uti_math import matr_prod, fwhm + +print('SRWLIB Python Example # 15:') +print('Calculating propagation of a gaussian beam through a drift and comparison with the analytical calculation.') + +#************************************* Create examples directory if it does not exist +example_folder = 'data_example_15' +if not os.path.isdir(example_folder): + os.mkdir(example_folder) + +#************************************* Auxiliary functions +def AnalyticEst(PhotonEnergy, WaistPozition, Waist, Dist): + """Perform analytical estimation""" + Lam = 1.24e-6 * PhotonEnergy + zR = 3.1415 * Waist ** 2 / Lam + wRMSan = [] + for l in range(len(Dist)): + wRMSan.append(1 * Waist * sqrt(1 + (Lam * (Dist[l] - WaistPozition) / 4 / 3.1415 / Waist ** 2) ** 2)) + return wRMSan + + +def BLMatrixMult(LensMatrX, LensMatrY, DriftMatr, DriftMatr0): + """Computes envelope in free space""" + InitDriftLenseX = matr_prod(LensMatrX, DriftMatr0) + tRMSfunX = matr_prod(DriftMatr, InitDriftLenseX) + InitDriftLenseY = matr_prod(LensMatrY, DriftMatr0) + tRMSfunY = matr_prod(DriftMatr, InitDriftLenseY) + return (tRMSfunX, tRMSfunY) + + +def Container(DriftLength, f_x, f_y): + """Container definition""" + OpElement = [] + ppOpElement = [] + OpElement.append(SRWLOptL(_Fx=f_x, _Fy=f_y, _x=0, _y=0)) + OpElement.append(SRWLOptD(DriftLength)) + ppOpElement.append([1, 1, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0]) # note that I use sel-adjust for Num grids + ppOpElement.append([1, 1, 1.0, 0, 0, 1.0, 1.0, 1.0, 1.0]) + OpElementContainer = [] + OpElementContainer.append(OpElement[0]) + OpElementContainer.append(OpElement[1]) + OpElementContainerProp = [] + OpElementContainerProp.append(ppOpElement[0]) + DriftMatr = [[1, DriftLength], [0, 1]] + OpElementContainerProp.append(ppOpElement[1]) + LensMatrX = [[1, 0], [-1.0 / f_x, 1]] + LensMatrY = [[1, 0], [-1.0 / f_y, 1]] + opBL = SRWLOptC(OpElementContainer, OpElementContainerProp) + return (opBL, LensMatrX, LensMatrY, DriftMatr) + + +def qParameter(PhotonEnergy, Waist, RadiusCurvature): + """Computing complex q parameter""" + Lam = 1.24e-6 * PhotonEnergy + qp = (1.0 + 0j) / complex(1 / RadiusCurvature, -Lam / 3.1415 / Waist ** 2) + return qp, Lam + +#************************************* 1. Defining Beam structure +GsnBm = SRWLGsnBm() # Gaussian Beam structure (just parameters) +GsnBm.x = 0 # Transverse Coordinates of Gaussian Beam Center at Waist [m] +GsnBm.y = 0 +GsnBm.z = 0 # Longitudinal Coordinate of Waist [m] +GsnBm.xp = 0 # Average Angles of Gaussian Beam at Waist [rad] +GsnBm.yp = 0 +GsnBm.avgPhotEn = 0.5 # 5000 #Photon Energy [eV] +GsnBm.pulseEn = 0.001 # Energy per Pulse [J] - to be corrected +GsnBm.repRate = 1 # Rep. Rate [Hz] - to be corrected +GsnBm.polar = 1 # 1- linear horizontal +GsnBm.sigX = 1e-03 # /2.35 #Horiz. RMS size at Waist [m] +GsnBm.sigY = 2e-03 # /2.35 #Vert. RMS size at Waist [m] +GsnBm.sigT = 10e-12 # Pulse duration [fs] (not used?) +GsnBm.mx = 0 # Transverse Gauss-Hermite Mode Orders +GsnBm.my = 0 + +#************************************* 2. Defining wavefront structure +wfr = SRWLWfr() # Initial Electric Field Wavefront +wfr.allocate(1, 100, 100) # Numbers of points vs Photon Energy (1), Horizontal and Vertical Positions (dummy) +wfr.mesh.zStart = 3.0 # Longitudinal Position [m] at which Electric Field has to be calculated, i.e. the position of the first optical element +wfr.mesh.eStart = GsnBm.avgPhotEn # Initial Photon Energy [eV] +wfr.mesh.eFin = GsnBm.avgPhotEn # Final Photon Energy [eV] +firstHorAp = 20.e-03 # First Aperture [m] +firstVertAp = 30.e-03 # [m] +wfr.mesh.xStart = -0.5 * firstHorAp # Initial Horizontal Position [m] +wfr.mesh.xFin = 0.5 * firstHorAp # Final Horizontal Position [m] +wfr.mesh.yStart = -0.5 * firstVertAp # Initial Vertical Position [m] +wfr.mesh.yFin = 0.5 * firstVertAp # Final Vertical Position [m] +DriftMatr0 = [[1, wfr.mesh.zStart], [0, 1]] + +#************************************* 3. Setting up propagation parameters +sampFactNxNyForProp = 5 # sampling factor for adjusting nx, ny (effective if > 0) +arPrecPar = [sampFactNxNyForProp] + +#************************************* 4. Defining optics properties +f_x = 3e+0 # focusing strength, m in X +f_y = 4e+0 # focusing strength, m in Y +StepSize = 0.3 # StepSize in meters along optical axis +InitialDist = 0 # Initial drift before start sampling RMS x/y after the lens +TotalLength = 6.0 # Total length after the lens +NumSteps = int((TotalLength - InitialDist) / StepSize) # Number of steps to sample RMS x/y after the lens + +#************************************* 5. Starting the cycle through the drift after the lens +xRMS = [] +yRMS = [] +s = [] +WRx = [] +WRy = [] +intensitiesToPlot = { # dict to store intensities and distances to plot at the end + 'intensity': [], + 'distance': [], + 'mesh': [], + 'mesh_x': [], + 'mesh_y': [] +} +# print('z xRMS yRMS mesh.nx mesh.ny xStart yStart') +# print('z xRMS yRMS nx ny xStart yStart') # OC +data_to_print = [] +#header = '{:3s} {:8s} {:8s} {:2s} {:2s} {:13s} {:13s}'.format('z', 'xRMS', 'yRMS', 'nx', 'ny', 'xStart', 'yStart') #MR27092016 +header = '{:3s} {:8s} {:8s} {:2s} {:2s} {:13s} {:13s}'.format('z', 'xFWHM', 'yFWHM', 'nx', 'ny', 'xStart', 'yStart') #OC18112017 +data_to_print.append(header) +print(header) +for j in range(NumSteps): + #********************************* Calculating Initial Wavefront and extracting Intensity: + srwl.CalcElecFieldGaussian(wfr, GsnBm, arPrecPar) + arI0 = array('f', [0] * wfr.mesh.nx * wfr.mesh.ny) # "flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arI0, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) # extracts intensity + wfrP = deepcopy(wfr) + + #********************************* Selecting radiation properties + Polar = 6 # 0- Linear Horizontal / 1- Linear Vertical 2- Linear 45 degrees / 3- Linear 135 degrees / 4- Circular Right / 5- Circular / 6- Total + Intens = 0 # 0=Single-e I/1=Multi-e I/2=Single-e F/3=Multi-e F/4=Single-e RadPhase/5=Re single-e Efield/6=Im single-e Efield + DependArg = 3 # 0 - vs e, 1 - vs x, 2 - vs y, 3- vs x&y, 4-vs x&e, 5-vs y&e, 6-vs x&y&e + # plotNum = 1000 + + if InitialDist == 0.0: # plot initial intensity at 0 + intensitiesToPlot['intensity'].append(deepcopy(arI0)) + intensitiesToPlot['distance'].append(InitialDist) + intensitiesToPlot['mesh_x'].append(deepcopy([wfrP.mesh.xStart, wfrP.mesh.xFin, wfrP.mesh.nx])) + intensitiesToPlot['mesh'].append(deepcopy(wfrP.mesh)) + intensitiesToPlot['mesh_y'].append(deepcopy([wfrP.mesh.yStart, wfrP.mesh.yFin, wfrP.mesh.ny])) + + InitialDist = InitialDist + StepSize + (opBL, LensMatrX, LensMatrY, DriftMatr) = Container(InitialDist, f_x, f_y) + srwl.PropagElecField(wfrP, opBL) # Propagate E-field + + # plotMeshx = [plotNum * wfrP.mesh.xStart, plotNum * wfrP.mesh.xFin, wfrP.mesh.nx] + # plotMeshy = [plotNum * wfrP.mesh.yStart, plotNum * wfrP.mesh.yFin, wfrP.mesh.ny] + plotMeshx = [wfrP.mesh.xStart, wfrP.mesh.xFin, wfrP.mesh.nx] + plotMeshy = [wfrP.mesh.yStart, wfrP.mesh.yFin, wfrP.mesh.ny] + + #********************************* Extracting output wavefront + arII = array('f', [0] * wfrP.mesh.nx * wfrP.mesh.ny) # "flat" array to take 2D intensity data + arIE = array('f', [0] * wfrP.mesh.nx * wfrP.mesh.ny) + srwl.CalcIntFromElecField(arII, wfrP, Polar, Intens, DependArg, wfrP.mesh.eStart, 0, 0) + arIx = array('f', [0] * wfrP.mesh.nx) + srwl.CalcIntFromElecField(arIx, wfrP, 6, Intens, 1, wfrP.mesh.eStart, 0, 0) + arIy = array('f', [0] * wfrP.mesh.ny) + srwl.CalcIntFromElecField(arIy, wfrP, 6, Intens, 2, wfrP.mesh.eStart, 0, 0) + + if abs(InitialDist - 3.0) < 1e-10 or abs(InitialDist - 3.9) < 1e-10: # plot at these distances + intensitiesToPlot['intensity'].append(deepcopy(arII)) + # intensitiesToPlot['distance'].append(InitialDist) + intensitiesToPlot['distance'].append(round(InitialDist, 6)) # OC + intensitiesToPlot['mesh_x'].append(deepcopy(plotMeshx)) + intensitiesToPlot['mesh'].append(deepcopy(wfrP.mesh)) + intensitiesToPlot['mesh_y'].append(deepcopy(plotMeshy)) + + x = [] + y = [] + arIxmax = max(arIx) + arIxh = [] + arIymax = max(arIx) + arIyh = [] + for i in range(wfrP.mesh.nx): + x.append((i - wfrP.mesh.nx / 2.0) / wfrP.mesh.nx * (wfrP.mesh.xFin - wfrP.mesh.xStart)) + arIxh.append(float(arIx[i] / arIxmax - 0.5)) + for i in range(wfrP.mesh.ny): + y.append((i - wfrP.mesh.ny / 2.0) / wfrP.mesh.ny * (wfrP.mesh.yFin - wfrP.mesh.yStart)) + arIyh.append(float(arIy[i] / arIymax - 0.5)) + xRMS.append(fwhm(x, arIxh)) + yRMS.append(fwhm(y, arIyh)) + s.append(InitialDist) + (tRMSfunX, tRMSfunY) = BLMatrixMult(LensMatrX, LensMatrY, DriftMatr, DriftMatr0) + WRx.append(tRMSfunX) + WRy.append(tRMSfunY) + # print(InitialDist, xRMS[j], yRMS[j], wfrP.mesh.nx, wfrP.mesh.ny, wfrP.mesh.xStart, wfrP.mesh.yStart) + # print(round(InitialDist, 6), round(xRMS[j], 6), round(yRMS[j], 6), wfrP.mesh.nx, wfrP.mesh.ny, + # round(wfrP.mesh.xStart, 10), round(wfrP.mesh.yStart, 10)) # OC + data_row = '{:3.1f} {:8.6f} {:8.6f} {:2d} {:2d} {:12.10f} {:12.10f}'.format(InitialDist, xRMS[j], yRMS[j], wfrP.mesh.nx, + wfrP.mesh.ny, wfrP.mesh.xStart, wfrP.mesh.yStart) #MR27092016 + data_to_print.append(data_row) + print(data_row) + +#************************************* 6. Analytic calculations +xRMSan = AnalyticEst(GsnBm.avgPhotEn, wfr.mesh.zStart + s[0], GsnBm.sigX, s) +(qxP, Lam) = qParameter(GsnBm.avgPhotEn, GsnBm.sigX, wfr.mesh.zStart + s[0]) +qx0 = complex(0, 3.1415 / Lam * GsnBm.sigX ** 2) +qy0 = complex(0, 3.1415 / Lam * GsnBm.sigY ** 2) +Wthx = [] +Wthy = [] +for m in range(len(s)): + Wx = (WRx[m][0][0] * qx0 + WRx[m][0][1]) / (WRx[m][1][0] * qx0 + WRx[m][1][1]) # MatrixMultiply(WR,qxP) + RMSbx = sqrt(1.0 / (-1.0 / Wx).imag / 3.1415 * Lam) * 2.35 + Wthx.append(RMSbx) + Wy = (WRy[m][0][0] * qy0 + WRy[m][0][1]) / (WRy[m][1][0] * qy0 + WRy[m][1][1]) # MatrixMultiply(WR,qxP) + RMSby = sqrt(1.0 / (-1.0 / Wy).imag / 3.1415 * Lam) * 2.35 + Wthy.append(RMSby) + +#************************************* 7. Plotting +for i in range(len(intensitiesToPlot['intensity'])): + srwl_uti_save_intens_ascii(intensitiesToPlot['intensity'][i], intensitiesToPlot['mesh'][i], + '{}/intensity_{:.1f}m.dat'.format(example_folder, intensitiesToPlot['distance'][i]), + 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], + _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + uti_plot.uti_plot2d1d(intensitiesToPlot['intensity'][i], + intensitiesToPlot['mesh_x'][i], + intensitiesToPlot['mesh_y'][i], + x=0, y=0, + labels=['Horizontal Position', 'Vertical Position', + 'Intenisty at {} m'.format(intensitiesToPlot['distance'][i])], + units=['m', 'm', 'a.u.']) + +with open('{}/compare.dat'.format(example_folder), 'w') as f: + f.write('\n'.join(data_to_print)) + +try: + from matplotlib import pyplot as plt + fig = plt.figure() + ax = fig.add_subplot(111) + ax.plot(s, xRMS, '-r.', label="X envelope from SRW") + ax.plot(s, Wthx, '--ro', label="X envelope from analytical estimate") + ax.plot(s, yRMS, '-b.', label="Y envelope from SRW") + ax.plot(s, Wthy, '--bo', label="Y envelope from analytical estimate") + ax.legend() + ax.set_xlabel('Distance along beam line [m]') + #ax.set_ylabel('Horizontal and Vertical RMS beam sizes [m]') + ax.set_ylabel('Horizontal and Vertical FWHM beam sizes [m]') #OC18112017 + ax.set_title('Gaussian beam envelopes through a drift after a lens') + ax.grid() + plt.savefig('{}/compare.png'.format(example_folder)) + plt.show() +except: + pass + +print('Exit') diff --git a/env/release/srw_python/SRWLIB_Example16.py b/env/release/srw_python/SRWLIB_Example16.py new file mode 100644 index 00000000..406c8845 --- /dev/null +++ b/env/release/srw_python/SRWLIB_Example16.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- + +""" +The example was created by Timur Shaftan (BNL) for RadTrack project (https://github.com/radiasoft/radtrack). +Adapted by Maksim Rakitin (BNL). +The purpose of the example is to demonstrate good agreement of the SRW simulation +of intensity distribution after diffraction on a circular aperture with an analytical approximation. + +The example requires SciPy library to perform comparison. +""" +from __future__ import print_function # Python 2.7 compatibility +import uti_plot +from srwlib import * +from uti_math import fwhm + +print('SRWLIB Python Example # 16:') +print('Calculation of intensity distribution due to diffraction on a circular aperture.') +try: + from scipy.special import jv + scipy_imported = True + print('Comparison with an analytical distribution...') +except: + scipy_imported = False + print('Can not import scipy for comparison of the numerically calculated intensity distribution with an analytical approximation.') + +#************************************* Create examples directory if it does not exist +example_folder = 'data_example_16' # example data sub-folder name +if not os.path.isdir(example_folder): + os.mkdir(example_folder) +strIntOutFileName = 'ex16_res_int.dat' # file name for output SR intensity data before propagation +strIntOutFileNameProp = 'ex16_res_int_prop_{}m.dat' # file name for output SR intensity data after propagation + +#************************************* Perform SRW calculations +# Gaussian beam definition: +GsnBm = SRWLGsnBm() +GsnBm.x = 0 # Transverse Coordinates of Gaussian Beam Center at Waist [m] +GsnBm.y = 0 +GsnBm.z = 0.0 # Longitudinal Coordinate of Waist [m] +GsnBm.xp = 0 # Average Angles of Gaussian Beam at Waist [rad] +GsnBm.yp = 0 +GsnBm.avgPhotEn = 0.5 # Photon Energy [eV] +GsnBm.pulseEn = 1.0E7 # Energy per Pulse [J] - to be corrected +GsnBm.repRate = 1 # Rep. Rate [Hz] - to be corrected +GsnBm.polar = 6 # 0- Linear Horizontal / 1- Linear Vertical 2- Linear 45 degrees / 3- Linear 135 degrees / 4- Circular Right / 5- Circular / 6- Total +GsnBm.sigX = 2.0E-3 # Horiz. RMS size at Waist [m] +GsnBm.sigY = 2.0E-3 # Vert. RMS size at Waist [m] +GsnBm.sigT = 1E-12 # Pulse duration [fs] (not used?) +GsnBm.mx = 0 # Transverse Gauss-Hermite Mode Orders +GsnBm.my = 0 + +# Wavefront definition: +wfr = SRWLWfr() +NEnergy = 1 # Number of points along Energy +Nx = 300 # Number of points along X +Ny = 300 # Number of points along Y +wfr.allocate(NEnergy, Nx, Ny) # Numbers of points vs Photon Energy (1), Horizontal and Vertical Positions (dummy) +wfr.mesh.zStart = 0.35 # Longitudinal Position [m] at which Electric Field has to be calculated, i.e. the position of the first optical element +wfr.mesh.eStart = 0.5 # Initial Photon Energy [eV] +wfr.mesh.eFin = 0.5 # Final Photon Energy [eV] +firstHorAp = 2.0E-3 # First Aperture [m] +firstVertAp = 2.0E-3 # [m] +wfr.mesh.xStart = -0.01 # Initial Horizontal Position [m] +wfr.mesh.xFin = 0.01 # Final Horizontal Position [m] +wfr.mesh.yStart = -0.01 # Initial Vertical Position [m] +wfr.mesh.yFin = 0.01 # Final Vertical Position [m] + +# Precision parameters for SR calculation: +meth = 2 # SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" +npTraj = 1 # number of points for trajectory calculation (not needed) +relPrec = 0.01 # relative precision +zStartInteg = 0.0 # longitudinal position to start integration (effective if < zEndInteg) +zEndInteg = 0.0 # longitudinal position to finish integration (effective if > zStartInteg) +useTermin = 1 # Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) +sampFactNxNyForProp = 1 # sampling factor for adjusting nx, ny (effective if > 0) +arPrecPar = [meth, relPrec, zStartInteg, zEndInteg, npTraj, useTermin, sampFactNxNyForProp] + +# Calculating initial wavefront: +srwl.CalcElecFieldGaussian(wfr, GsnBm, arPrecPar) +meshIn = deepcopy(wfr.mesh) +wfrIn = deepcopy(wfr) + +arIin = array('f', [0] * wfrIn.mesh.nx * wfrIn.mesh.ny) +srwl.CalcIntFromElecField(arIin, wfrIn, 0, 0, 3, wfr.mesh.eStart, 0, 0) + +arIinY = array('f', [0] * wfrIn.mesh.ny) +srwl.CalcIntFromElecField(arIinY, wfrIn, 0, 0, 2, wfrIn.mesh.eStart, 0, 0) # extracts intensity + +# Plotting initial wavefront: +plotMeshInX = [1000 * wfrIn.mesh.xStart, 1000 * wfrIn.mesh.xFin, wfrIn.mesh.nx] +plotMeshInY = [1000 * wfrIn.mesh.yStart, 1000 * wfrIn.mesh.yFin, wfrIn.mesh.ny] +srwl_uti_save_intens_ascii(arIin, wfrIn.mesh, + '{}/{}'.format(example_folder, strIntOutFileName), + 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], + #_arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + _arUnits=['eV', 'm', 'm', 'arb. units']) +uti_plot.uti_plot2d1d(arIin, plotMeshInX, plotMeshInY, + #labels=['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intensity Before Propagation [a.u.]']) + labels=['Horizontal Position', 'Vertical Position', 'Intensity Before Propagation'], + units=['mm', 'mm', 'arb. units']) + +# Element definition: +apertureSize = 0.00075 # Aperture radius, m +defaultDriftLength = 1.0 # Drift length, m +OpElement = [] +ppOpElement = [] + +OpElement.append(SRWLOptA('c', 'a', apertureSize, apertureSize)) +ppOpElement.append([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0]) +arIinymax = [] +for k, driftLength in enumerate([0.0, defaultDriftLength]): + ppOpElement.append([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0]) + if driftLength: + OpElement.append(SRWLOptD(driftLength)) # Drift space + ppOpElement.append([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0, 0, 0]) + + opBL = SRWLOptC(OpElement, ppOpElement) + srwl.PropagElecField(wfr, opBL) # Propagate Electric Field + + polarization = 6 #0- Linear Horizontal / 1- Linear Vertical / 2- Linear 45 degrees / 3- Linear 135 degrees / 4- Circular Right / 5- Circular / 6- Total + intensity = 0 #0- Single-e Int. / 1- Multi-e Int. / 2- Single-e Flux / 3- Multi-e Flux / 4- Single-e Rad. Phase / 5- Re Single-e E-field / 6- Im Single-e E-field + dependArg = 3 #0- vs e / 1- vs x / 2- vs y / 3- vs x&y / 4- vs x&e / 5- vs y&e / 6- vs x&y&e + + # Calculating output wavefront: + arIout = array('f', [0] * wfr.mesh.nx * wfr.mesh.ny) # "flat" array to take 2D intensity data + arII = arIout + arIE = array('f', [0] * wfr.mesh.nx * wfr.mesh.ny) + srwl.CalcIntFromElecField(arII, wfr, polarization, intensity, dependArg, wfr.mesh.eStart, 0, 0) + + arI1y = array('f', [0] * wfr.mesh.ny) + arRe = array('f', [0] * wfr.mesh.ny) + arIm = array('f', [0] * wfr.mesh.ny) + srwl.CalcIntFromElecField(arI1y, wfr, polarization, intensity, 2, wfr.mesh.eStart, 0, 0) # extracts intensity + + # Normalize intensities: + arI1ymax = max(arI1y) + arIinymax.append(max(arIinY)) + for i in range(len(arI1y)): + arI1y[i] /= arI1ymax + for i in range(len(arIinY)): + arIinY[i] /= arIinymax[-1] + + # Plotting output wavefront: + plotNum = 1000 + plotMeshx = [plotNum * wfr.mesh.xStart, plotNum * wfr.mesh.xFin, wfr.mesh.nx] + plotMeshy = [plotNum * wfr.mesh.yStart, plotNum * wfr.mesh.yFin, wfr.mesh.ny] + srwl_uti_save_intens_ascii(arII, wfr.mesh, + '{}/{}'.format(example_folder, strIntOutFileNameProp.format(driftLength)), + 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], + _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + uti_plot.uti_plot2d1d(arII, plotMeshx, plotMeshy, + #labels=['Horizontal Position [mm]', 'Vertical Position [mm]', 'Intenisty at {}m After Aperture [a.u.]'.format(driftLength)]) + labels=['Horizontal Position', 'Vertical Position', 'Intenisty at {} m After Aperture'.format(driftLength)], + units=['mm', 'mm', 'arb. units']) + + srwl.CalcIntFromElecField(arRe, wfr, polarization, 5, 2, wfr.mesh.eStart, 0, 0) + srwl.CalcIntFromElecField(arIm, wfr, polarization, 6, 2, wfr.mesh.eStart, 0, 0) + +def calc_fwhm(intensities, wavefront, shift=0.5, mesh=True, factor=1e3): + if mesh: + y = [] + for i in range(wfrIn.mesh.ny): + y.append((i - wavefront.mesh.ny / 2.0) / wavefront.mesh.ny * (wavefront.mesh.yFin - wavefront.mesh.yStart)) + else: + y = wavefront + + renormed_intensities = [] + max_intensity = max(intensities) + for i in intensities: + renormed_intensities.append(float(i / max_intensity - shift)) + return fwhm(y, renormed_intensities) * factor # in [mm] by default + +parameters = [ + ['Maximum intensity before and after propagation', arIinymax[0], arI1ymax], + ['Number of horizontal mesh points before and after propagation', wfrIn.mesh.nx, wfr.mesh.nx], + ['Number of vertical mesh points before and after propagation', wfrIn.mesh.ny, wfr.mesh.ny], + ['Wavefront horizontal start coordinates [mm] before and after propagation', wfrIn.mesh.xStart, wfr.mesh.xStart], + ['Wavefront horizontal end coordinates [mm] before and after propagation', wfrIn.mesh.xFin, wfr.mesh.xFin], + ['Wavefront vertical start coordinates [mm] before and after propagation', wfrIn.mesh.yStart, wfr.mesh.yStart], + ['Wavefront vertical end coordinates [mm] before and after propagation', wfrIn.mesh.yFin, wfr.mesh.yFin], + ['Vertical FWHM [mm] before and after propagation', calc_fwhm(arIinY, wfrIn), calc_fwhm(arI1y, wfr)], +] +for i in range(len(parameters)): + print('{}{}: [{}, {}]'.format(' ', *parameters[i])) + +#************************************* 2. Defining parameters for analytic calculation +lam = 2.4796e-6 # 1.2398/0.5 eV +numPointsIn = len(arIinY) +numPointsOut = len(arI1y) +meshSize = float(wfr.mesh.xFin) + +#************************************* 3. Computing intensity distribution as per Born & Wolf, Principles of Optics +th = [] +sIn = [] +sOut = [] +analyticalIntens = [] +for i in range(numPointsOut): + thx = 2.0 * (i - numPointsOut / 2.0 + 0.5) * meshSize / numPointsOut / driftLength + th.append(thx) + sOut.append(thx * driftLength * 1000) +if scipy_imported: + for i in range(numPointsOut): + x = 3.1415 * apertureSize * sin(th[i]) / lam + analyticalIntens.append((2 * jv(1, x) / x) ** 2) + print('{}Analytical FWHM [mm]: {}'.format(' ', calc_fwhm(analyticalIntens, sOut, mesh=False, factor=1.0))) +for i in range(numPointsIn): + sIn.append(2000.0 * (i - numPointsIn / 2.0) * float(wfrIn.mesh.xFin) / numPointsIn) + +#************************************* 4. Plotting +try: + from matplotlib import pyplot as plt + fig = plt.figure(figsize=(10, 7)) + ax = fig.add_subplot(111) + ax.plot(sIn, arIinY, '--g.', label='SRW (before aperture)') + ax.plot(sOut, arI1y, '-r.', label='SRW ({}m after aperture)'.format(driftLength)) + if analyticalIntens: + ax.plot(sOut, analyticalIntens, '-b.', label='Analytical estimation') + ax.legend() + ax.set_xlabel('Vertical Position [mm]') + ax.set_ylabel('Normalized Intensity') + ax.set_title('Intensity Before and After Propagation\n(cut vs vertical position at x=0)') + ax.grid() + plt.savefig('{}/compare.png'.format(example_folder)) + plt.show() +except: + pass + +print('done') diff --git a/env/release/srw_python/SRWLIB_ExampleViewDataFile.py b/env/release/srw_python/SRWLIB_ExampleViewDataFile.py new file mode 100644 index 00000000..20eebb60 --- /dev/null +++ b/env/release/srw_python/SRWLIB_ExampleViewDataFile.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLIB Example View Data File: View data stored in a file +# v 0.04 +# Authors: O.C., Maksim Rakitin +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from uti_plot import * +import optparse +import os + +if __name__=='__main__': + p = optparse.OptionParser() + p.add_option('-f', '--infile', dest='infile', metavar='FILE', default='', help='input file name') + p.add_option('-e', '--e', dest='e', metavar='NUMBER', type='float', default=0, help='photon energy') + p.add_option('-x', '--x', dest='x', metavar='NUMBER', type='float', default=0, help='horizontal position') + p.add_option('-y', '--y', dest='y', metavar='NUMBER', type='float', default=0, help='vertical position') + p.add_option('-l', '--readlab', dest='readlab', metavar='NUMBER', type='int', nargs=0, default=0, help='read labels from the file header (1) or not (0)') + p.add_option('-j', '--joined', dest='joined', metavar='NUMBER', type='int', nargs=0, default=0, help='place different graphs jointly into one figure (1) or into separate figures (0)') + #p.add_option('-t', '--traj-report', dest='traj_report', metavar='NUMBER', action='store_true', default=0, help='plot trajectory report') #MR29072016 + #p.add_option('-a', '--traj-axis', dest='traj_axis', metavar='STR', default='x', help='trajectory coordinate ("x" or "y")') #MR29072016 + p.add_option('-m', '--multicol_data', dest='multicol_data', metavar='NUMBER', action='store_true', default=0, help='visualize multicolumn data') #OC14112017 #MR31102017 + p.add_option('--m_colx', dest='multicol_data_col_x', metavar='STR', default=None, help='column for horizontal axis') #OC14112017 #MR31102017 + p.add_option('--m_coly', dest='multicol_data_col_y', metavar='STR', default=None, help='column for vertical axis') #OC14112017 #MR31102017 + p.add_option('-s', '--scale', dest='scale', metavar='SCALE', default='linear', help='scale to use in plots (linear, log, log2, log10)') #MR20012017 + p.add_option('-w', '--width-pixels', dest='width_pixels', metavar='WIDTH', default=None, help='desired width of pixels') #MR22122016 + + opt, args = p.parse_args() + + if opt.readlab != 0: opt.readlab = 1 + if opt.joined != 0: opt.joined = 1 + + #if len(opt.infile) == 0: + # print('File name was not specified. Use -f option to specify the file name with path.') + # quit() + + #print(opt.infile) + if not os.path.isfile(opt.infile): #MR31102017 + p.error('File name is not specified or is incorrect. Use -f option to specify the file name with path.') + + if opt.multicol_data and not (opt.multicol_data_col_x and opt.multicol_data_col_y): #OC14112017 #MR31102017 + p.error('Specify columns for horizontal (--m_colx) and vertical (--m_coly) axes for multicolumn data plot.') + + #print(opt.joined) + uti_plot_init('TkAgg') + #uti_data_file_plot(opt.infile, opt.readlab, opt.e, opt.x, opt.y, opt.joined) + #uti_data_file_plot(opt.infile, opt.readlab, opt.e, opt.x, opt.y, opt.joined, opt.traj_report, opt.traj_axis) #MR29072016 + #uti_data_file_plot(opt.infile, opt.readlab, opt.e, opt.x, opt.y, opt.joined, opt.traj_report, opt.traj_axis, opt.log_scale, opt.width_pixels) #MR22122016 + #uti_data_file_plot(opt.infile, opt.readlab, opt.e, opt.x, opt.y, opt.joined, opt.traj_report, opt.traj_axis, opt.scale, opt.width_pixels) #MR29072016 + uti_plot_data_file(opt.infile, opt.readlab, opt.e, opt.x, opt.y, opt.joined, + opt.multicol_data, opt.multicol_data_col_x, opt.multicol_data_col_y, #OC14112017 #MR31102017 + opt.scale, opt.width_pixels) + + uti_plot_show() diff --git a/env/release/srw_python/SRWLIB_ExamplesRunAll.py b/env/release/srw_python/SRWLIB_ExamplesRunAll.py new file mode 100644 index 00000000..b3bad7d8 --- /dev/null +++ b/env/release/srw_python/SRWLIB_ExamplesRunAll.py @@ -0,0 +1,36 @@ +############################################################################# +# SRWLIB Examples: Runs all SRW Examples +# v 0.01 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +import os + +print('SRWLIB Python Examples: run all') +print('***Running all SRW Python examples one by one***') + +exFileNames = [ + 'SRWLIB_Example01.py', + 'SRWLIB_Example01_kick_matr.py', + 'SRWLIB_Example02.py', + 'SRWLIB_Example03.py', + 'SRWLIB_Example04.py', + 'SRWLIB_Example05.py', + 'SRWLIB_Example06.py', + 'SRWLIB_Example06_PETRA.py', + 'SRWLIB_Example07.py', + 'SRWLIB_Example08.py', + 'SRWLIB_Example09.py', + 'SRWLIB_Example10.py', + 'SRWLIB_Example11.py', + 'SRWLIB_Example12.py', + 'SRWLIB_Example13.py', + 'SRWLIB_Example14.py', + 'SRWLIB_Example15.py', + 'SRWLIB_Example16.py', + ] + +for i in range(len(exFileNames)): + scriptName = exFileNames[i] + print('Starting', scriptName + '.', 'When done testing, close its windows to continue.') + os.system('python ' + scriptName) diff --git a/env/release/srw_python/data_example_11/dummy.txt b/env/release/srw_python/data_example_11/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_11/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/data_example_12/dummy.txt b/env/release/srw_python/data_example_12/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_12/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/data_example_13/dummy.txt b/env/release/srw_python/data_example_13/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_13/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/data_example_14/dummy.txt b/env/release/srw_python/data_example_14/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_14/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/data_example_15/dummy.txt b/env/release/srw_python/data_example_15/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_15/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/data_example_16/dummy.txt b/env/release/srw_python/data_example_16/dummy.txt new file mode 100644 index 00000000..252337dc --- /dev/null +++ b/env/release/srw_python/data_example_16/dummy.txt @@ -0,0 +1 @@ +dummy file to make folder non-empty \ No newline at end of file diff --git a/env/release/srw_python/lib/libsrw_x86_64.a b/env/release/srw_python/lib/libsrw_x86_64.a index 3e826844..9eb1c7cb 100644 Binary files a/env/release/srw_python/lib/libsrw_x86_64.a and b/env/release/srw_python/lib/libsrw_x86_64.a differ diff --git a/env/release/srw_python/lib/libsrw_x86_64.a.old b/env/release/srw_python/lib/libsrw_x86_64.a.old new file mode 100644 index 00000000..0a741a59 Binary files /dev/null and b/env/release/srw_python/lib/libsrw_x86_64.a.old differ diff --git a/env/release/srw_python/lib/srw_win32.lib b/env/release/srw_python/lib/srw_win32.lib index d0f77af3..7bf4c174 100644 Binary files a/env/release/srw_python/lib/srw_win32.lib and b/env/release/srw_python/lib/srw_win32.lib differ diff --git a/env/release/srw_python/lib/srw_x64.lib b/env/release/srw_python/lib/srw_x64.lib index 765fa0e1..ccfe9c91 100644 Binary files a/env/release/srw_python/lib/srw_x64.lib and b/env/release/srw_python/lib/srw_x64.lib differ diff --git a/env/release/srw_python/lib/srwlib.h b/env/release/srw_python/lib/srwlib.h index ae94fda8..a7b59e0a 100644 --- a/env/release/srw_python/lib/srwlib.h +++ b/env/release/srw_python/lib/srwlib.h @@ -119,6 +119,7 @@ struct SRWLStructMagneticFieldMultipole { char n_or_s; /* normal ('n') or skew ('s') */ double Leff; /* effective length [m] */ double Ledge; /* "soft" edge length for field variation from 10% to 90% [m]; G/(1 + ((z-zc)/d)^2)^2 fringe field dependence is assumed */ + double R; /* radius of curvature of central trajectory [m] (for simulating e.g. quadrupole component integrated to a bending magnet; effective if > 0) */ }; typedef struct SRWLStructMagneticFieldMultipole SRWLMagFldM; @@ -165,9 +166,17 @@ typedef struct SRWLStructMagneticFieldUndulator SRWLMagFldU; struct SRWLStructMagneticFieldContainer { void **arMagFld; /* array of pointers to magnetic field elements */ char *arMagFldTypes; /* types of magnetic field elements in arMagFld array */ - double *arXc; /* horizontal center positions of magnetic field elements in arMagFld array */ - double *arYc; /* vertical center positions of magnetic field elements in arMagFld array */ - double *arZc; /* longitudinal center positions of magnetic field elements in arMagFld array */ + double *arXc; /* horizontal center positions of magnetic field elements in arMagFld array [m] */ + double *arYc; /* vertical center positions of magnetic field elements in arMagFld array [m] */ + double *arZc; /* longitudinal center positions of magnetic field elements in arMagFld array [m] */ + double *arVx; /* horizontal components of axis vectors of magnetic field elements in arMagFld array [rad] */ + double *arVy; /* vertical components of axis vectors of magnetic field elements in arMagFld array [rad] */ + double *arVz; /* longitudinal components of axis vectors of magnetic field elements in arMagFld array [rad] */ + double *arAng; /* rotation angles of magnetic field elements about their axes [rad] */ + double *arPar1; /* optional array of parameter values the elements of the magnet array correspond to (to be used e.g. for finding undulator magnetic field for a particular gap/phase value by interpolation) */ + double *arPar2; /* optional array of parameter values the elements of the magnet array correspond to (to be used e.g. for finding undulator magnetic field for a particular gap/phase value by interpolation) */ + double *arPar3; /* optional array of parameter values the elements of the magnet array correspond to */ + double *arPar4; /* optional array of parameter values the elements of the magnet array correspond to */ int nElem; /* number of magnetic field elements in arMagFld array */ }; typedef struct SRWLStructMagneticFieldContainer SRWLMagFldC; @@ -177,7 +186,8 @@ typedef struct SRWLStructMagneticFieldContainer SRWLMagFldC; */ struct SRWLStructParticleTrajectory { double *arX, *arXp, *arY, *arYp, *arZ, *arZp; /* arrays of horizontal, vertical and longitudinal positions and relative velocities */ - int np; /* number of trajectory points */ + double *arBx, *arBy, *arBz; /* arrays of horizontal, vertical and longitudinal magnetic field components 'seen' by particle (along trajectory) */ + long long np; /* int np; number of trajectory points */ double ctStart, ctEnd; /* start and end values of independent variable (c*t) for which the trajectory should be (/is) calculated (is constant step enough?) */ SRWLParticle partInitCond; /* particle type and initial conditions for which the trajectory should be (/is) calculated */ }; @@ -211,6 +221,17 @@ struct SRWLStructGaussianBeam { }; typedef struct SRWLStructGaussianBeam SRWLGsnBm; +/** + * Coherent Gaussian Beam + */ +struct SRWLStructPointSource { + double x, y, z; /* coordinates [m] */ + double flux; /* spectral flux */ + char unitFlux; /* spectral flux units: 1- ph/s/.1%bw, 2- W/eV */ + char polar; /* polarization: 1- lin. hor., 2- lin. vert., 3- lin. 45 deg., 4- lin.135 deg., 5- circ. right, 6- circ. left, 7- radial */ +}; +typedef struct SRWLStructPointSource SRWLPtSrc; + /** * Radiation Mesh (for Electric Field, Stokes params, etc.) * TENTATIVE VERSION ! @@ -218,6 +239,8 @@ typedef struct SRWLStructGaussianBeam SRWLGsnBm; struct SRWLStructRadMesh { double eStart, eFin, xStart, xFin, yStart, yFin, zStart; /* initial and final values of photon energy (/time), horizontal, vertical and longitudinal positions */ long ne, nx, ny; /* numbers of points vs photon energy, horizontal and vertical positions */ + double nvx, nvy, nvz, hvx, hvy, hvz; /* lab-frame coordinate of the inner normal to observation plane (/ surface in its center) and horizontal base vector of the observation plane (/ surface in its center) */ + double *arSurf; /* array defining the observation surface (as function of 2 variables - x & y - on the mesh given by _xStart, _xFin, _nx, _yStart, _yFin, _ny; to be used in case this surface differs from plane) */ }; typedef struct SRWLStructRadMesh SRWLRadMesh; @@ -227,6 +250,7 @@ typedef struct SRWLStructRadMesh SRWLRadMesh; */ struct SRWLStructWaveFront { char *arEx, *arEy; /* horizontal and vertical electric field component arrays */ + char *arExAux, *arEyAux; /* auxiliary horizontal and vertical electric field component arrays (to be used e.g. at resizing) */ //double eStart, eFin, xStart, xFin, yStart, yFin, zStart; /* initial and final values of photon energy (/time), horizontal, vertical and longitudinal positions */ //long ne, nx, ny; /* numbers of points vs photon energy, horizontal and vertical positions */ SRWLRadMesh mesh; @@ -240,7 +264,8 @@ struct SRWLStructWaveFront { char presCA; /* presentation/domain: 0- coordinates, 1- angles */ char presFT; /* presentation/domain: 0- frequency (photon energy), 1- time */ char numTypeElFld; /* electric field numerical type: 'f' (float) or 'd' (double) */ - char unitElFld; /* electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2) ? */ + char unitElFld; /* electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) ? */ + char unitElFldAng; /* electric field units in angular representation: 0- sqrt(Wavelength[m]*Phot/s/0.1%bw/mrad^2) vs rad/Wavelength[m], 1- sqrt(Phot/s/0.1%bw/mrad^2) vs rad; [Phot/s/0.1%bw] can be replaced by [J/eV] or [W], depending on unitElFld, presFT and presCA */ SRWLPartBeam partBeam; /* particle beam source; strictly speaking, it should be just SRWLParticle; however, "multi-electron" information can appear useful for those cases when "multi-electron intensity" can be deduced from the "single-electron" one by convolution */ double *arElecPropMatr; /* effective 1st order "propagation matrix" for electron beam parameters */ @@ -274,6 +299,7 @@ typedef struct SRWLStructStokes SRWLStokes; */ struct SRWLStructOpticsDrift { double L; /* length [m] */ + char treat; /* switch specifying whether the absolute optical path should be taken into account in radiation phase (=1) or not (=0, default) */ }; typedef struct SRWLStructOpticsDrift SRWLOptD; @@ -299,6 +325,24 @@ struct SRWLStructOpticsLens { }; typedef struct SRWLStructOpticsLens SRWLOptL; +/** + * Optical Element: + * Angle ("angle" type) + */ +struct SRWLStructOpticsAngle { + double AngX, AngY; /* horizontal and vertical angles [rad] */ +}; +typedef struct SRWLStructOpticsAngle SRWLOptAng; + +/** + * Optical Element: + * Shift ("shift" type) + */ +struct SRWLStructOpticsShift { + double ShiftX, ShiftY; /* horizontal and vertical shifts [m] */ +}; +typedef struct SRWLStructOpticsShift SRWLOptShift; + /** * Optical Element: * Zone Plate ("zp" type) @@ -324,30 +368,20 @@ struct SRWLStructOpticsWaveguide { }; typedef struct SRWLStructOpticsWaveguide SRWLOptWG; -/** - * Optical Element: - * Grating (plane) ("grating" type) - */ -struct SRWLStructOpticsGrating { - double grDen; /* groove density [lines/mm] */ - char disPl; /* dispersion plane: 'x' ('h') or 'y' ('v') */ - double ang; /* angle between optical axis and grating plane [rad] */ - int m; /* output order to be used */ - double refl; /* average reflectivity (with resp. to intensity) */ -}; -typedef struct SRWLStructOpticsGrating SRWLOptG; - /** * Optical Element: * Transmission ("transmission" type) */ struct SRWLStructOpticsTransmission { double *arTr; /* complex C-aligned data array (of 2*nx*ny length) storing amplitude transmission and optical path difference as function of transverse position */ - int nx, ny; /* numbers of transmission data points in the horizontal and vertical directions */ - double rx, ry; /* ranges of horizontal and vertical coordinates [m] for which the transmission is defined */ + + SRWLStructRadMesh mesh; //mesh vs photon energy, horizontal and vertical positions + + //int nx, ny; /* numbers of transmission data points in the horizontal and vertical directions */ + //double rx, ry; /* ranges of horizontal and vertical coordinates [m] for which the transmission is defined */ char extTr; /* 0- transmission outside the grid/mesh is zero; 1- it is same as on boundary */ double Fx, Fy; /* estimated focal lengths [m] */ - double x, y; /* transverse coordinates of center [m] */ + //double x, y; /* transverse coordinates of center [m] */ }; typedef struct SRWLStructOpticsTransmission SRWLOptT; @@ -374,15 +408,24 @@ struct SRWLStructOpticsMirror { double reflAngStart, reflAngFin; /* initial and final grazing angle values for which the reflectivity coefficient is specified */ char reflPhEnScaleType[4], reflAngScaleType[4]; /* photon energy and angle sampling type (1 for linear, 2 for logarithmic) */ - double nvx, nvy, nvz; /* horizontal, vertical and longitudinal coordinates of central normal vector [m] in the frame of incident beam */ - double tvx, tvy; /* horizontal and vertical coordinates of central tangential vector [m] in the frame of incident beam */ + double nvx, nvy, nvz; /* horizontal, vertical and longitudinal coordinates of central normal vector in the frame of incident beam */ + double tvx, tvy; /* horizontal and vertical coordinates of central tangential vector in the frame of incident beam */ double x, y; /* transverse coordinates of center [m] */ }; typedef struct SRWLStructOpticsMirror SRWLOptMir; /** * Optical Element: - * Ellipsoidal Mirror + * Plane Mirror ("mirror: plane" type) + */ +struct SRWLStructOpticsMirrorPlane { + SRWLOptMir baseMir; /* general information about the mirror */ +}; +typedef struct SRWLStructOpticsMirrorPlane SRWLOptMirPl; + +/** + * Optical Element: + * Ellipsoidal Mirror ("mirror: ellipsoid" type) */ struct SRWLStructOpticsMirrorEllipsoid { double p, q; /* distance [m] from first focus ('source') to mirror center, and from center to second focus ('image') */ @@ -394,7 +437,7 @@ typedef struct SRWLStructOpticsMirrorEllipsoid SRWLOptMirEl; /** * Optical Element: - * Toroidal Mirror + * Toroidal Mirror ("mirror: toroid" type) */ struct SRWLStructOpticsMirrorToroid { double radTan, radSag; /* tangential and sagital radii of the torus [m] */ @@ -402,6 +445,49 @@ struct SRWLStructOpticsMirrorToroid { }; typedef struct SRWLStructOpticsMirrorToroid SRWLOptMirTor; +/** +* Optical Element: +* Spherical Mirror ("mirror: sphere" type) +*/ +struct SRWLStructOpticsMirrorSphere { + double rad; /* radius of the sphere [m] */ + SRWLOptMir baseMir; /* general information about the mirror */ +}; +typedef struct SRWLStructOpticsMirrorSphere SRWLOptMirSph; + +/** + * Optical Element: + * Grating ("grating" type) + */ +struct SRWLStructOpticsGrating { + void *mirSub; /* pointer to a mirror object defining the grating substrate */ + char mirSubType[256]; /* array of types of optical elements (C strings) in arOpt array */ + int m; /* output (diffraction) order to be used */ + double grDen; /* grove density [lines/mm] (coefficient a0 in the polynomial groove density: a0 + a1*y + a2*y^2 + a3*y^3 + a4*y^4) */ + double grDen1, grDen2, grDen3, grDen4; /* groove density polynomial coefficients a1 [lines/mm^2], a2 [lines/mm^3], a3 [lines/mm^4], a4 [lines/mm^5]*/ + double grAng; /* angle between the grove direction and the saggital direction of the substrate [rad] */ +}; +typedef struct SRWLStructOpticsGrating SRWLOptG; + +/** + * Optical Element: + * Ideal Crystal + */ +struct SRWLStructOpticsCrystal { + double dSp; /* crystal reflecting planes d-spacing (units?) */ + double psi0r, psi0i; /* real and imaginary parts of 0-th Fourier component of crystal polarizability (units?) */ + double psiHr, psiHi; /* real and imaginary parts of H-th Fourier component of crystal polarizability (units?) */ + double psiHbr, psiHbi; /* real and imaginary parts of -H-th Fourier component of crystal polarizability (units?) */ + //double h1, h2, h3; /* 1st, 2nd and 3rd indexes of diffraction vector (Miller indices) */ + //OC180314: the Miller indices are removed after discussion with A. Suvorov (because these are only required for the dSp, and it is used as input parameter) + double tc; /* crystal thickness [m] */ + double angAs; /* asymmetry angle [rad] */ + double nvx, nvy, nvz; /* horizontal, vertical and longitudinal coordinates of outward normal to crystal surface in the frame of incident beam */ + double tvx, tvy; /* horizontal and vertical coordinates of central tangential vector [m] in the frame of incident beam */ + char uc; /* crystal use case: 1- Bragg Reflection, 2- Bragg Transmission (Laue cases to be added) */ +}; +typedef struct SRWLStructOpticsCrystal SRWLOptCryst; + /** * Optical Element: * Container ("container" type) @@ -411,6 +497,7 @@ struct SRWLStructOpticsContainer { char **arOptTypes; /* array of types of optical elements (C strings) in arOpt array */ int nElem; /* number of magnetic field elements in arMagFld array */ double **arProp; /* array of arrays of propagation parameters to be used for individual optical elements */ + char *arPropN; /* array of numbers of propagation parameters for each optical element */ int nProp; /* number of propagation instructions (length of arProp array); can be nProp <= (nElem + 1); if nProp == (nElem + 1), last resizing is applied after the propagation */ }; @@ -451,6 +538,22 @@ EXP int CALL srwlUtiVerNo(char* verNoStr, int code); */ EXP int CALL srwlUtiGetErrText(char* t, int erNo); +/** + * Calculates (tabulates) 3D magnetic field created by multiple elements + * @param [in, out] pDispMagFld pointer to resulting magnetic field container with one element - 3D magnetic field structure to keep the tabulated field data (all arrays should be allocated in a calling function/application) + * @param [in] pMagFld pointer to input magnetic field (container) structure + * @param [in] precPar optional array of precision parameters + * precPar[0] defines the type of calculation: =0 -standard calculation, =1 -interpolation vs one parameter, =2 -interpolation vs two parameters + * [1]: first parameter value the field has to be interpolated for + * [2]: second parameter value the field has to be interpolated for + * [3]: specifies type (order) of interpolation: =1 -(bi-)linear, =2 -(bi-)quadratic, =3 -(bi-)cubic + * [4]: specifies whether mesh for the interpolation is rectangular (1) or not (0) + * [5]: specifies whether pMagFld contains just the field required for the interpolation (1) or the required fields have to be found from the general list (0) + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlCalcMagFld(SRWLMagFldC* pDispMagFld, SRWLMagFldC* pMagFld, double* precPar =0); + /** * Calculates charged particle trajectory in external 3D magnetic field (in Cartesian laboratory frame) * @param [in, out] pTrj pointer to resulting trajectory structure (all data arrays should be allocated in a calling function/application); the initial conditions and particle type must be specified in pTrj->partInitCond; the initial conditions are assumed to be defined for ct = 0, however the trajectory will be calculated for the mesh defined by pTrj->np, pTrj->ctStart, pTrj->ctEnd @@ -458,8 +561,8 @@ EXP int CALL srwlUtiGetErrText(char* t, int erNo); * @param [in] precPar (optional) method ID and precision parameters; * if(precPar == 0) default 4th-order Runge-Kutta method is used; otherwise: * precPar[0] is number of precision parameters that will follow - * [1] method number: 1- 4th-order Runge-Kutta; 2- 5th-order Runge-Kutta; - * [2] interpolation method to use for tabulated magnetic field: 1- simple bi-linear (3D); 2- bi-quadratic (3D); 3- bi-cubic (3D); 4- 1D cubic spline + 2D bi-cubic + * [1]: method number: 1- 4th-order Runge-Kutta; 2- 5th-order Runge-Kutta; + * [2]: interpolation method to use for tabulated magnetic field: 1- simple bi-linear (3D); 2- bi-quadratic (3D); 3- bi-cubic (3D); 4- 1D cubic spline + 2D bi-cubic * [3],[4],[5],[6],[7]: absolute precision values for X[m],X'[rad],Y[m],Y'[rad],Z[m] (yet to be tested!!) - to be taken into account only for R-K fifth order or higher * [8]: rel. tolerance for R-K fifth order or higher (default = 1) * [9]: max. number of auto-steps for R-K fifth order or higher (default = 5000) @@ -486,17 +589,19 @@ EXP int CALL srwlCalcPartTrajFromKickMatr(SRWLPrtTrj* pTrj, SRWLKickM* arKickM, * @param [in] pTrj pointer to pre-calculated particle trajectory structure; the initial conditions and particle type must be specified in pTrj->partInitCond; if the trajectory data arrays (pTrj->arX, pTrj->arXp, pTrj->arY, pTrj->arYp) are defined, the SR will be calculated from these data; if these arrays are not supplied (pointers are zero), the function will attempt to calculate the SR from the magnetic field data (pMagFld) which has to be supplied * @param [in] pMagFld optional pointer to input magnetic field (container) structure; to be taken into account only if particle trajectroy arrays (pTrj->arX, pTrj->arXp, pTrj->arY, pTrj->arYp) are not supplied * @param [in] precPar precision parameters: - * precPar[0]: method ID (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") - * [1]: step size or relative precision - * [2]: longitudinal position to start integration - * [3]: longitudinal position to finish integration - * [4]: number of points to use for trajectory calculation - * [5]:... - * [6]: sampling factor (for propagation, effective if > 0) + * precPar[0]: method ID (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") + * [1]: step size or relative precision + * [2]: longitudinal position to start integration + * [3]: longitudinal position to finish integration + * [4]: number of points to use for trajectory calculation + * [5]: calculate terminating terms or not: 0- don't calculate two terms, 1- do calculate two terms, 2- calculate only upstream term, 3- calculate only downstream term + * [6]: sampling factor (for propagation, effective if > 0) + * [7]: ... + * @param [in] nPrecPar number of precision parameters * @return integer error (>0) or warnig (<0) code * @see ... */ -EXP int CALL srwlCalcElecFieldSR(SRWLWfr* pWfr, SRWLPrtTrj* pTrj, SRWLMagFldC* pMagFld, double* precPar =0); +EXP int CALL srwlCalcElecFieldSR(SRWLWfr* pWfr, SRWLPrtTrj* pTrj, SRWLMagFldC* pMagFld, double* precPar =0, int nPrecPar =0); /** * Calculates Electric Field (Wavefront) of a coherent Gaussian Beam @@ -508,11 +613,21 @@ EXP int CALL srwlCalcElecFieldSR(SRWLWfr* pWfr, SRWLPrtTrj* pTrj, SRWLMagFldC* p */ EXP int CALL srwlCalcElecFieldGaussian(SRWLWfr* pWfr, SRWLGsnBm* pGsnBm, double* precPar =0); +/** + * Calculates Electric Field (Wavefront) of a Pont Source (i.e. spherical wave) + * @param [in, out] pWfr pointer to resulting Wavefront structure; all data arrays should be allocated in a calling function/application; the mesh, presentation, etc., should be specified in this structure at input + * @param [in] pPtSrc pointer to a Point Source parameters structure + * @param [in] precPar precision parameters: [0]- sampling factor (for propagation, effective if > 0), + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlCalcElecFieldPointSrc(SRWLWfr* pWfr, SRWLPtSrc* pPtSrc, double* precPar =0); + /** * Calculates Spectral Flux (Stokes components) of Synchrotron Radiation by a relativistic finite-emittance electron beam traveling in periodic magnetic field of an Undulator * @param [in, out] pStokes pointer to the resulting Stokes structure; all data arrays should be allocated in a calling function/application; the mesh, presentation, etc., should be specified in this structure at input - * @param [in] pElBeam pointer to input electron beam structure - * @param [in] pUnd pointer to input undulator (periodic magnetic field) structure + * @param [in] pElBeam pointer to input electron beam structure + * @param [in] pUnd pointer to input undulator (periodic magnetic field) structure * @param [in] precPar precision parameters: * precPar[0]: initial harmonic * [1]: final harmonic @@ -549,26 +664,27 @@ EXP int CALL srwlCalcPowDenSR(SRWLStokes* pStokes, SRWLPartBeam* pElBeam, SRWLPr * 0- Linear Horizontal; * 1- Linear Vertical; * 2- Linear 45 degrees; - * 3- Linear 135 degrees; + * 3- Linear 135 degrees; * 4- Circular Right; * 5- Circular Left; * 6- Total * @param [in] intType "type" of a characteristic to be extracted: - * 0- Single-Electron Intensity; - * 1- Multi-Electron Intensity; - * 2- Single-Electron Flux; - * 3- Multi-Electron Flux; - * 4- Single-Electron Radiation Phase; + * 0- "Single-Electron" Intensity; + * 1- "Multi-Electron" Intensity; + * 2- "Single-Electron" Flux; + * 3- "Multi-Electron" Flux; + * 4- "Single-Electron" Radiation Phase; * 5- Re(E): Real part of Single-Electron Electric Field; - * 6- Im(E): Imaginary part of Single-Electron Electric Field + * 6- Im(E): Imaginary part of Single-Electron Electric Field; + * 7- "Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence); * @param [in] depType type of dependence to extract: - * 0- vs e (photon energy or time); - * 1- vs x (horizontal position or angle); - * 2- vs y (vertical position or angle); - * 3- vs x&y; (horizontal and vertical positions or angles); - * 4- vs e&x; - * 5- e&y; - * 6- vs e&x&y + * 0- vs e (photon energy or time); + * 1- vs x (horizontal position or angle); + * 2- vs y (vertical position or angle); + * 3- vs x&y (horizontal and vertical positions or angles); + * 4- vs e&x (photon energy or time and horizontal position or angle); + * 5- vs e&y (photon energy or time and vertical position or angle); + * 6- vs e&x&y (photon energy or time, horizontal and vertical positions or angles); * @param [in] e photon energy (to keep fixed) * @param [in] x horizontal position (to keep fixed) * @param [in] y vertical position (to keep fixed) @@ -582,11 +698,19 @@ EXP int CALL srwlCalcIntFromElecField(char* pInt, SRWLWfr* pWfr, char pol, char * @param [in, out] pWfr pointer to pre-calculated Wavefront structure * @param [in] type character specifying whether the resizing should be done vs coordinates/angles ('c') or vs photon energy/time ('f') * @param [in] par array of parameters: - * [0]- method (0- regular method, without FFT, 1- "special" method involving FFT), - * [1]- range resizing factor for horizontal poosition / angle (if type == 'c') or for photon energy / time (if type == 'f') - * [2]- resolution resizing factor for horizontal poosition / angle (if type == 'c') or for photon energy / time (if type == 'f') - * [3]- range resizing factor for vertical poosition / angle (effective only if type == 'c') - * [4]- resolution resizing factor for vertical poosition / angle (effective only if type == 'c') + * if(type == 'c'): + * [0]- method (0- regular method, without FFT, 1- "special" method involving FFT) + * [1]- range resizing factor for horizontal position / angle + * [2]- resolution resizing factor for horizontal position / angle + * [3]- range resizing factor for vertical position / angle + * [4]- resolution resizing factor for vertical position / angle + * [5]- relative horizontal wavefront center position / angle at resizing (default is 0.5) + * [6]- relative vertical wavefront center position / angle at resizing (default is 0.5) + * if(type == 'f'): + * [0]- method (0- regular method, without FFT, 1- "special" method involving FFT) + * [1]- range resizing factor for photon energy / time + * [2]- resolution resizing factor for photon energy / time + * [3]- relative photon energy / time center position at resizing (default is 0.5) * @return integer error (>0) or warnig (<0) code * @see ... */ @@ -624,6 +748,75 @@ EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt); */ EXP int CALL srwlPropagRadMultiE(SRWLStokes* pStokes, SRWLWfr* pWfr0, SRWLOptC* pOpt, double* precPar, int (*pExtFunc)(int action, SRWLStokes* pStokesInst)); +/** + * Performs FFT (1D or 2D, depending on arguments) + * @param [in, out] pcData (char) pointer to data to be FFT-ed + * @param [in] typeData character specifying data type ('f' for float, 'd' for double) + * @param [in] arMesh array describing mesh parameters of the data to be FFT-ed: + * arMesh[0]: start value of the first argument + * arMesh[1]: step value of the first argument + * arMesh[2]: number of points of the first argument + * arMesh[3]: (optional) start value of the second argument + * arMesh[4]: (optional) step value of the second argument + * arMesh[5]: (optional) number of points of the second argument + * @param [in] nMesh length of arMesh array (3 or 6 elements) + * @param [in] dir direction for the FFT (>0 means forward, <0 means backward) + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiFFT(char* pcData, char typeData, double* arMesh, int nMesh, int dir); + +/** + * Convolves real data with 1D or 2D Gaussian (depending on arguments) + * @param [in, out] pcData (char) pointer to data to be convolved + * @param [in] typeData character specifying data type ('f' for float, 'd' for double) + * @param [in] arMesh array describing mesh parameters of the data to be convolved: + * arMesh[0]: start value of the first argument + * arMesh[1]: step value of the first argument + * arMesh[2]: number of points of the first argument + * arMesh[3]: (optional) start value of the second argument + * arMesh[4]: (optional) step value of the second argument + * arMesh[5]: (optional) number of points of the second argument + * @param [in] nMesh length of arMesh array (3 or 6 elements) + * @param [in] arSig array of RMS values of the 2D Gaussian and, possibly, coefficient before cross-term; + i.e. arSig[] = {SigX, SigY, Alp} defines a 'tilted' 2D Gaussian (normalized to 1): + (sqrt(1 - (Alp*SigX*SigY)^2)/(2*Pi*SigX*SigY))*Exp[-x^2/(2*SigX^2) - y^2/(2*SigY^2) - Alp*x*y] + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiConvWithGaussian(char* pcData, char typeData, double* arMesh, int nMesh, double* arSig); + +/** + * Attempts to deduce parameters of peridic undulator magnetic field from tabulated field and set up Undulator structure + * @param [in, out] pUndCnt pointer to magnetic field container structure with undulator structure to be set up + * @param [in] pMagCnt pointer to magnetic field container structure with tabulated field structure to be analyzed + * @param [in] arPrecPar array of precision parameters: + * arPrecPar[0]: relative accuracy threshold + * arPrecPar[1]: maximal number of magnetic field harmonics to attempt to create + * arPrecPar[2]: maximal magnetic period length + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiUndFromMagFldTab(SRWLMagFldC* pUndCnt, SRWLMagFldC* pMagCnt, double* arPrecPar); + +/** + * Attempts to find indexes of undulator gap and phase values and associated magnetic fields requiired to be used in field interpolation based on gap and phase + * @param [in, out] arResInds array of indexes to be found + * @param [in, out] pnResInds pointer to number of indexes found + * @param [in] arGaps array of undulator gap values + * @param [in] arPhases array of undulator phase values + * @param [in] nVals number of undulator gap and phase values + * @param [in] arPrecPar array of precision parameters: + * arPrecPar[0]: number of dimensions (1 if only gaps should be considered; 2 if both gaps and phases should be considered) + * arPrecPar[1]: gap value for which interpolation should be done + * arPrecPar[2]: phase value for which interpolation should be done + * arPrecPar[3]: order of interpolation (1 to 3) + * arPrecPar[4]: mesh is rectangular (0 for no, 1 for yes) + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiUndFindMagFldInterpInds(int* arResInds, int* pnResInds, double* arGaps, double* arPhases, int nVals, double arPrecPar[5]); + /***************************************************************************/ #ifdef __cplusplus diff --git a/env/release/srw_python/lib/srwlpy2_7_win32.pyd b/env/release/srw_python/lib/srwlpy2_7_win32.pyd new file mode 100644 index 00000000..62adf7d3 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_win32.pyd differ diff --git a/env/release/srw_python/lib/srwlpy2_7_win32.pyd.old b/env/release/srw_python/lib/srwlpy2_7_win32.pyd.old new file mode 100644 index 00000000..6e167871 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_win32.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy2_7_x64.pyd b/env/release/srw_python/lib/srwlpy2_7_x64.pyd new file mode 100644 index 00000000..22d82dd7 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_x64.pyd differ diff --git a/env/release/srw_python/lib/srwlpy2_7_x64.pyd.old b/env/release/srw_python/lib/srwlpy2_7_x64.pyd.old new file mode 100644 index 00000000..804e1d37 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_x64.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy2_7_x86_64.so b/env/release/srw_python/lib/srwlpy2_7_x86_64.so new file mode 100644 index 00000000..2e06874e Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_x86_64.so differ diff --git a/env/release/srw_python/lib/srwlpy2_7_x86_64.so.old b/env/release/srw_python/lib/srwlpy2_7_x86_64.so.old new file mode 100644 index 00000000..d006328d Binary files /dev/null and b/env/release/srw_python/lib/srwlpy2_7_x86_64.so.old differ diff --git a/env/work/srw_python/lib/srwlpy3_2_x86_64.so.old b/env/release/srw_python/lib/srwlpy3_2_x86_64.so.old similarity index 100% rename from env/work/srw_python/lib/srwlpy3_2_x86_64.so.old rename to env/release/srw_python/lib/srwlpy3_2_x86_64.so.old diff --git a/env/release/srw_python/lib/srwlpy3_3_win32.pyd b/env/release/srw_python/lib/srwlpy3_3_win32.pyd new file mode 100644 index 00000000..6d783ac0 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_3_win32.pyd differ diff --git a/env/release/srw_python/lib/srwlpy3_3_win32.pyd.old b/env/release/srw_python/lib/srwlpy3_3_win32.pyd.old new file mode 100644 index 00000000..a434cdd6 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_3_win32.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy3_3_x64.pyd b/env/release/srw_python/lib/srwlpy3_3_x64.pyd new file mode 100644 index 00000000..9fe0b8cf Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_3_x64.pyd differ diff --git a/env/release/srw_python/lib/srwlpy3_3_x64.pyd.old b/env/release/srw_python/lib/srwlpy3_3_x64.pyd.old new file mode 100644 index 00000000..1ba13224 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_3_x64.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy3_5_x64.pyd b/env/release/srw_python/lib/srwlpy3_5_x64.pyd new file mode 100644 index 00000000..36bd318e Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_5_x64.pyd differ diff --git a/env/release/srw_python/lib/srwlpy3_5_x64.pyd.old b/env/release/srw_python/lib/srwlpy3_5_x64.pyd.old new file mode 100644 index 00000000..31243bcb Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_5_x64.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy3_6_win32.pyd b/env/release/srw_python/lib/srwlpy3_6_win32.pyd new file mode 100644 index 00000000..31c61d60 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_6_win32.pyd differ diff --git a/env/release/srw_python/lib/srwlpy3_6_win32.pyd.old b/env/release/srw_python/lib/srwlpy3_6_win32.pyd.old new file mode 100644 index 00000000..9175ed8e Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_6_win32.pyd.old differ diff --git a/env/release/srw_python/lib/srwlpy3_6_x64.pyd b/env/release/srw_python/lib/srwlpy3_6_x64.pyd new file mode 100644 index 00000000..186dc81f Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_6_x64.pyd differ diff --git a/env/release/srw_python/lib/srwlpy3_6_x64.pyd.old b/env/release/srw_python/lib/srwlpy3_6_x64.pyd.old new file mode 100644 index 00000000..65547662 Binary files /dev/null and b/env/release/srw_python/lib/srwlpy3_6_x64.pyd.old differ diff --git a/env/release/srw_python/srwl_bl.py b/env/release/srw_python/srwl_bl.py new file mode 100644 index 00000000..80d1ec5f --- /dev/null +++ b/env/release/srw_python/srwl_bl.py @@ -0,0 +1,3202 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRWLib SR Beamline Base Class +# Contains a set of member objects and functions for simulating basic operation and characteristics +# of a complete user beamline in a synchrotron radiation source. +# Under development!!! +# Authors/Contributors: O.C., Maksim Rakitin +# v 0.06 +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from srwlib import * +from srwl_uti_mag import * +from srwl_uti_und import * +from uti_plot import * +import uti_math +#import optparse #MR081032016 #Consider placing import argparse here +import time + +try: #OC05042018 + import cPickle as pickle +except: + import pickle + +#**************************************************************************** +class SRWLBeamline(object): + """Basic Synchrotron Radiation Beamline (in a storage ring based source) + Several different types of simulations are planned to be supported, including: + - single-electron UR intensity spectrum; + - UR spectrum through a slit (finite aperture), taking into account e-beam emittance and energy spread; + - single-electron (fully-coherent) and multi-electron (partially-coherent) wavefront propagation calculations; + - simulation of (coherent scattering type) experiments for different types of samples and beamline settings; + - misc. auxiliary calculations/estimations facilitating beamline operation (e.g. estimation of undulator gap and crystal monochromator angle for a required photon energy, etc.) + """ + + #------------------------------------------------------------------------ + def __init__(self, _name='', _e_beam=None, _mag_approx=None, _mag=None, _gsn_beam=None, _op=None): #, _det=None): + """ + :param _name: beamline name string + :param _e_beam: electron beam (SRWLPartBeam instance) + :param _mag_approx: approximate magnetic field container (SRWLMagFldC instance) + :param _mag: accurate magnetic field container (SRWLMagFldC instance) + :param _gsn_beam: coherent Gaussian beam (SRWLGsnBm instance) + :param _op: optics sequence (SRWLOptC instance) + :param _det: detector (SRWLDet instance) + """ + + if _e_beam is not None: + if(isinstance(_e_beam, SRWLPartBeam) == False): + raise Exception("Incorrect Electron Beam structure") + if _mag_approx is not None: + if(isinstance(_mag_approx, SRWLMagFldC) == False): + raise Exception("Incorrect Magnetic Field Container structure") + if _mag is not None: + if(isinstance(_mag, SRWLMagFldC) == False): + raise Exception("Incorrect Magnetic Field Container structure") + if _gsn_beam is not None: + if(isinstance(_gsn_beam, SRWLGsnBm) == False): + raise Exception("Incorrect Gaussian Beam structure") + if _op is not None: + if(isinstance(_op, SRWLOptC) == False): + raise Exception("Incorrect Optical Container structure") + #if _det != None: + # if(isinstance(_det, SRWLDet) == False): + # raise Exception("Incorrect Detector structure") + + self.name = _name + self.eBeam = SRWLPartBeam() if _e_beam is None else _e_beam + self.mag_approx = _mag_approx + self.mag = _mag + self.gsnBeam = _gsn_beam + self.optics = _op + #self.detector = _det + + #------------------------------------------------------------------------ +## def set_e_beam(self, _e_beam_name='', _e_beam=None, _i=-1, _sig_e=-1, _emit_x=-1, _emit_y=-1, _drift=0, _x=0, _y=0, _xp=0, _yp=0, _dE=0): +## """Setup Electron Beam. +## NOTE: The beam is assumed to be first set up at z = 0 longitudinal position, and then it is propagated according to _drift (if _drift != 0.) +## :param _e_beam_name: e-beam unique name, e.g. 'NSLS-II Low Beta Day 1' (see srwl_uti_src.py) +## :param _e_beam: e-beam structure (SRWLPartBeam instance) +## :param _i: e-beam current [A] +## :param _sig_e: e-beam relative energy spread +## :param _emit_x: e-beam horizontal emittance +## :param _emit_y: e-beam vertical emittance +## :param _drift: e-beam drift length in [m] from center of straight section +## :param _x: initial average horizontal position [m] +## :param _y: initial average vertical position [m] +## :param _xp: initial average horizontal angle [m] +## :param _yp: initial average vertical angle [m] +## :param _dE0: average energy deviation [GeV] +## """ +## #add more parameters when/if necessary +## +## if(_sig_e < 0.): _sig_e = None +## if(_emit_x < 0.): _emit_x = None +## if(_emit_y < 0.): _emit_y = None +## +## sIncInpElecBeam = 'Incorrect input for setting up Electron Beam structure' +## if(len(_e_beam_name) > 0): +## self.eBeam = srwl_uti_src_e_beam(_e_beam_name, _sig_e=_sig_e, _emit_x=_emit_x, _emit_y=_emit_y) +## if(self.eBeam == None): +## if((_e_beam == None) or (isinstance(_e_beam, SRWLPartBeam) == False)): +## raise Exception(sIncInpElecBeam) +## else: self.eBeam = _e_beam +## else: +## if((_e_beam == None) or (isinstance(_e_beam, SRWLPartBeam) == False)): +## raise Exception(sIncInpElecBeam) +## else: self.eBeam = _e_beam +## +## #OC: Add Twiss parameters and 2nd order moments to function arguments and program logic of switching bw these definitions +## #OC: consider treating _sig_e=-1, _emit_x=-1, _emit_y=-1 is defined, in all cases! +## +## if(_i > 0): self.eBeam.Iavg = _i +## if(_drift != 0): self.eBeam.drift(_drift) +## self.eBeam.partStatMom1.x = _x +## self.eBeam.partStatMom1.y = _y +## self.eBeam.partStatMom1.xp = _xp +## self.eBeam.partStatMom1.yp = _yp +## +## if(_dE != 0): +## elRestMassGeV = 0.51099890221e-03 +## curE0 = self.eBeam.partStatMom1.gamma*self.eBeam.partStatMom1.relE0*elRestMassGeV +## self.eBeam.partStatMom1.gamma = (curE0 + _dE)/(self.eBeam.partStatMom1.relE0*elRestMassGeV) + + #------------------------------------------------------------------------ + def set_e_beam(self, _e_beam_name='', _e_beam=None, _i=-1, _ens=-1, _emx=-1, _emy=-1, _dr=0, _x=0, _y=0, _xp=0, _yp=0, _e=None, _de=0, + _betax=None, _alphax=None, _etax=None, _etaxp=None, _betay=None, _alphay=None, _etay=0, _etayp=0, + _sigx=None, _sigxp=None, _mxxp=None, _sigy=None, _sigyp=None, _myyp=None): + """Setup Electron Beam + + :param _e_beam_name: e-beam unique name, e.g. 'NSLS-II Low Beta Day 1' (see srwl_uti_src.py) + :param _e_beam: e-beam structure (SRWLPartBeam instance) + :param _i: e-beam current [A] + :param _ens: e-beam relative energy spread + :param _emx: e-beam horizontal emittance + :param _emy: e-beam vertical emittance + :param _dr: e-beam drift length in [m] from center of straight section + :param _x: initial average horizontal position [m] + :param _y: initial average vertical position [m] + :param _xp: initial average horizontal angle [m] + :param _yp: initial average vertical angle [m] + :param _e: energy [GeV] + :param _de: average energy deviation [GeV] + + #MR28092016 - added parameters to define the beam explicitly: + # Parameters for SRWLPartBeam.from_Twiss(): + # def from_Twiss(self, _Iavg=0, _e=0, _sig_e=0, _emit_x=0, _beta_x=0, _alpha_x=0, _eta_x=0, _eta_x_pr=0, _emit_y=0, _beta_y=0, _alpha_y=0, _eta_y=0, _eta_y_pr=0): + :param _betax: horizontal beta-function [m] + :param _alphax: horizontal alpha-function [rad] + :param _etax: horizontal dispersion function [m] + :param _etaxp: horizontal dispersion function derivative [rad] + :param _betay: vertical beta-function [m] + :param _alphay: vertical alpha-function [rad] + :param _etay: vertical dispersion function [m] + :param _etayp: vertical dispersion function derivative [rad] + + # Parameters for SRWLPartBeam.from_RMS(): + # def from_RMS(self, _Iavg=0, _e=0, _sig_e=0, _sig_x=0, _sig_x_pr=0, _m_xx_pr=0, _sig_y=0, _sig_y_pr=0, _m_yy_pr=0): + :param _sigx: horizontal RMS size [m] + :param _sigxp: horizontal RMS divergence [rad] + :param _mxxp: <(x-)(x'-)> [m] + :param _sigy: vertical RMS size [m] + :param _sigyp: vertical RMS divergence [rad] + :param _myyp: <(y-)(y'-)> [m] + """ + #add more parameters when/if necessary + + #print('In set_e_beam: x=', _x, ' xp=', _xp) + + varParamStd = srwl_uti_std_options() + help_dict = {} + for v in varParamStd: + help_dict[v[0]] = '{}{}'.format(v[3][0].upper(), v[3][1:]) + + def check_positive(d): + for k, v in d.items(): + if v is None or v < 0: + return False, k + return True, None + + if(_ens < 0.): _ens = None + if(_emx < 0.): _emx = None + if(_emy < 0.): _emy = None + + sIncInpElecBeam = 'Incorrect input for setting up Electron Beam structure' + + eBeamWasSetFromDB = False #OC28092016 + if len(_e_beam_name) > 0: + self.eBeam = srwl_uti_src_e_beam(_e_beam_name, _sig_e=_ens, _emit_x=_emx, _emit_y=_emy) + eBeamWasSetFromDB = True + if self.eBeam is None: + if (_e_beam is None) or (isinstance(_e_beam, SRWLPartBeam) is False): + # raise ValueError(sIncInpElecBeam) + raise ValueError('The beam name "{}" was not found in the database and _e_beam is empty'.format(_e_beam_name)) + else: + self.eBeam = _e_beam + + eBeamWasSetFromInObj = False + if((eBeamWasSetFromDB is False) and (isinstance(_e_beam, SRWLPartBeam) is True)): + self.eBeam = _e_beam + eBeamWasSetFromInObj = True + + if((eBeamWasSetFromDB is False) and (eBeamWasSetFromInObj is False)): #Try to set up e-beam from input Twiss params or Moments + + #beam_inputs = {'_i': _i, '_e': _e, '_ens': _ens} + #beam_check, beam_bad_var = check_positive(beam_inputs) + #if beam_check: + ##OC15092017 removed the above check because for partially-coherent calculations with Gaussian beam _i, _e, _ens can be 0 or undefined + twiss_inputs = {'_emx': _emx, '_betax': _betax, '_etax': _etax, + '_emy': _emy, '_betay': _betay, '_etay': _etay} + moments_inputs = {'_sigx': _sigx, '_sigxp': _sigxp, + '_sigy': _sigy, '_sigyp': _sigyp} + twiss_check, twiss_bad_var = check_positive(twiss_inputs) + if((_alphax is None) or (_alphay is None)): twiss_check = False #OC28092016 + if((_etaxp is None) or (_etayp is None)): twiss_check = False + + moments_check, moments_bad_var = check_positive(moments_inputs) + if((_mxxp is None) or (_myyp is None)): moments_check = False #OC28092016 + + if twiss_check: + # Defined by Twiss parameters: + self.eBeam.from_Twiss( + _Iavg=_i, _e=_e, _sig_e=_ens, + _emit_x=_emx, _beta_x=_betax, _alpha_x=_alphax, _eta_x=_etax, _eta_x_pr=_etaxp, + _emit_y=_emy, _beta_y=_betay, _alpha_y=_alphay, _eta_y=_etay, _eta_y_pr=_etayp, + ) + elif moments_check: + # Defined by Moments: + self.eBeam.from_RMS( + _Iavg=_i, _e=_e, _sig_e=_ens, + _sig_x=_sigx, _sig_x_pr=_sigxp, _m_xx_pr=_mxxp, + _sig_y=_sigy, _sig_y_pr=_sigyp, _m_yy_pr=_myyp, + ) + else: + # raise ValueError(sIncInpElecBeam) + err_msg = 'Twiss and/or Moments parameters are not set correctly:\n - {} ({}): {}\n - {} ({}): {}\n' + raise ValueError(err_msg.format( + help_dict['ebm{}'.format(twiss_bad_var)], twiss_bad_var, twiss_inputs[twiss_bad_var], + help_dict['ebm{}'.format(moments_bad_var)], moments_bad_var, moments_inputs[moments_bad_var], + )) + #else: + # err_msg = 'Beam parameters are not set correctly:\n - {} ({}): {}\n' + # raise ValueError(err_msg.format( + # help_dict['ebm{}'.format(beam_bad_var)], beam_bad_var, beam_inputs[beam_bad_var], + # )) + + else: #Allow overriding some 2nd order moments if eBeamWasSetFromDB or eBeamWasSetFromInObj + + if((_ens is not None) and (_ens > 0)): self.eBeam.arStatMom2[10] = _ens*_ens + if((_sigx is not None) and (_sigx > 0)): self.eBeam.arStatMom2[0] = _sigx*_sigx + if((_sigxp is not None) and (_sigxp > 0)): self.eBeam.arStatMom2[2] = _sigxp*_sigxp + if((_mxxp is not None) and (_mxxp != 1.e+23)): self.eBeam.arStatMom2[1] = _mxxp + if((_sigy is not None) and (_sigy > 0)): self.eBeam.arStatMom2[3] = _sigy*_sigy + if((_sigyp is not None) and (_sigyp > 0)): self.eBeam.arStatMom2[5] = _sigyp*_sigyp + if((_myyp is not None) and (_myyp != 1.e+23)): self.eBeam.arStatMom2[4] = _myyp + + #Allow applying drift and overriding 1st order moments in any case + #if((_dr is not None) and (_dr != 0)): self.eBeam.drift(_dr) #OC16032017: moved to after the following lines + + if((_i is not None) and (_i > 0)): self.eBeam.Iavg = _i + if(_x is not None): self.eBeam.partStatMom1.x = _x + if(_y is not None): self.eBeam.partStatMom1.y = _y + if(_xp is not None): self.eBeam.partStatMom1.xp = _xp + if(_yp is not None): self.eBeam.partStatMom1.yp = _yp + + if((_dr is not None) and (_dr != 0)): self.eBeam.drift(_dr) #OC16032017 (see above) + + if((_de is not None) and (_de != 0)): + elRestMassGeV = 0.51099890221e-03 + curE0 = self.eBeam.partStatMom1.gamma*self.eBeam.partStatMom1.relE0*elRestMassGeV + self.eBeam.partStatMom1.gamma = (curE0 + _de)/(self.eBeam.partStatMom1.relE0*elRestMassGeV) + + #------------------------------------------------------------------------ + def set_und_sin(self, _per=0.02, _len=1, _bx=0, _by=0, _phx=0, _phy=0, _sx=1, _sy=1, _zc=0, _add=0): + """Setup magnetic field container with basic undulator having sinusoidal magnetic field + :param _per: period length [m] + :param _len: undulator length [m] + :param _bx: horizontal magnetic field amplitude [m] + :param _by: vertical magnetic field amplitude [m] + :param _phx: initial phase of the horizontal magnetic field [rad] + :param _phx: initial phase of the vertical magnetic field [rad] + :param _sx: symmetry of the horizontal magnetic field vs longitudinal position 1 - symmetric (B ~ cos(2*Pi*n*z/per + ph)) , -1 - anti-symmetric (B ~ sin(2*Pi*n*z/per + ph)) + :param _sy: symmetry of the vertical magnetic field vs longitudinal position + :param _zc: longitudinal position of the undulator center + :param _reset: add (=1) or reset (=0) the new undulator structure to the existing approximate magnetic field container + """ + + if(_add == 0): + if(self.mag_approx is not None): + del self.mag_approx + + if(self.mag_approx is None): self.mag_approx = SRWLMagFldC() + + und = SRWLMagFldU() + und.set_sin(_per, _len, _bx, _by, _phx, _phy, _sx, _sy) + self.mag_approx.arMagFld.append(und) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + #print(self.mag_approx.arVx) + + return self.mag_approx + + #------------------------------------------------------------------------ + def set_mag_multipole(self, _bx=0, _by=1., _gn=0, _gs=0, _len=1.5, _led=0, _r=0, _zc=0, _add=0): + """Setup magnetic field container with basic dipole / quadrupole magnet + :param _bx: horizontal magnetic field [m] + :param _by: vertical magnetic field [m] + :param _gn: magnetic field gradient of normal quad [m] + :param _gs: magnetic field gradient of skew quad [m] + :param _len: magnet length [m] + :param _led: "soft" edge length for field variation from 10% to 90% [m]; G/(1 + ((z-zc)/d)^2)^2 fringe field dependence is assumed [m] + :param _zc: longitudinal position of the magnet center + :param _add: add (=1) or reset (=0) the new magnet structure to the existing approximate magnetic field container + """ + + if(_add == 0): + if(self.mag_approx is not None): + del self.mag_approx + + if(self.mag_approx is None): self.mag_approx = SRWLMagFldC() + + if(_bx != 0): + dipBx = SRWLMagFldM(_G=_bx, _m=1, _n_or_s='s', _Leff=_len, _Ledge=_led, _R=_r) #? + self.mag_approx.arMagFld.append(dipBx) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + if(_by != 0): + dipBy = SRWLMagFldM(_G=_by, _m=1, _n_or_s='n', _Leff=_len, _Ledge=_led, _R=_r) + self.mag_approx.arMagFld.append(dipBy) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + if(_gn != 0): + quadN = SRWLMagFldM(_G=_gn, _m=2, _n_or_s='n', _Leff=_len, _Ledge=_led, _R=_r) + self.mag_approx.arMagFld.append(quadN) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + if(_gs != 0): + quadS = SRWLMagFldM(_G=_gs, _m=2, _n_or_s='s', _Leff=_len, _Ledge=_led, _R=_r) + self.mag_approx.arMagFld.append(quadS) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + #print('At the end of set_mag_multipole, mag_approx:', self.mag_approx) + return self.mag_approx + + #------------------------------------------------------------------------ + def set_mag_kick(self, _angx=1., _angy=0, _len=1., _led=0, _zc=0, _add=0): + """Setup magnetic field container with basic dipole "kick" magnet + :param _angx: horizontal kick angle [rad] + :param _angy: vertical kick angle [rad] + :param _len: magnet length [m] + :param _led: "soft" edge length for field variation from 10% to 90% [m]; G/(1 + ((z-zc)/d)^2)^2 fringe field dependence is assumed [m] + :param _zc: longitudinal position of the magnet center + :param _add: add (=1) or reset (=0) the new magnet structure to the existing approximate magnetic field container + """ + + if(self.eBeam is None): raise Exception('Electron Beam structure is not defined (it is required for defining kick magnet parameters from angle)') + elEn_GeV = self.eBeam.partStatMom1.get_E(_unit='GeV') + + if(_add == 0): + if(self.mag_approx is not None): del self.mag_approx + + if(_angx != 0.): + kickMag = srwl_mag_kick(_el_en=elEn_GeV, _ang=_angx, _x_or_y='x', _len=_len, _led=_led) + self.mag_approx.arMagFld.append(kickMag) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + if(_angy != 0.): + kickMag = srwl_mag_kick(_el_en=elEn_GeV, _ang=_angy, _x_or_y='y', _len=_len, _led=_led) + self.mag_approx.arMagFld.append(kickMag) + self.mag_approx.arXc.append(0) + self.mag_approx.arYc.append(0) + self.mag_approx.arZc.append(_zc) + + return self.mag_approx + + #------------------------------------------------------------------------ + def set_und_tab_total(self, _gap, _ph_mode='p1', _phase=0., _zc=0., _interp_ord=1, _meas_or_calc='m', _per=0.02, _c1=0, _c2=0, _a=0, _dg_by_len=0, _y0=0, _yp=0): + #def set_und_tab(self, _gap, _ph_mode='p1', _phase=0., _zc=0., _interp_ord=1, _meas_or_calc='m', _per=0.02, _c1=0, _c2=0, _a=0, _dg_by_len=0, _y0=0, _yp=0): + """Setup magnetic field container with magnetic measurements or calculation data interpolated for given gap and phase + :param _gap: magnetic gap [mm] for which the field should be set up + :param _ph_mode: type of phase (shift of magnet arrays) motion + :param _phase: shift of magnet arrays [mm] for which the field should be set up + :param _zc: center position [m] + :param _interp_ord: order of interpolation: 1- (bi-)linear, 2- (bi-)quadratic, 3- (bi-)cubic + :param _meas_or_calc: use magnetic measurements ('m') or calculation ('c') data + :param _per: undulator period [m] + :param _c1: constant defining (approximate) undulator field dependence on gap (i.e. c1 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _c2: constant defining (approximate) undulator field dependence on gap (i.e. c2 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _a: constant defining (approximate) undulator field dependence on vertical position (i.e. a in cosh(2*Pi*a*y/per) + :param _dg_by_len: gap taper (exit minus entrance) divided by undulator length + :param _y0: vertical electron position in the center of undulator relative to undulator median plane [m] + :param _dydz: vertical electron angle in the center of undulator relative to undulator median plane [rad] + """ + + fPathSum = '' + if(_meas_or_calc == 'm'): + if(hasattr(self, 'dir_magn_meas') and hasattr(self, 'fn_magn_meas_sum')): + fPathSum = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, self.fn_magn_meas_sum) + else: raise Exception('No magnetic measurements data are supplied') + elif(_meas_or_calc == 'c'): + raise Exception('No magnetic calculation data are supplied') + + f = open(fPathSum, 'r') + lines = f.readlines() #read-in all lines + nRows = len(lines) + + strSep = '\t' + arGaps = []; arPhases = []; arMagFld3D = [] + arXc = []; arYc = []; arZc = [] + arCoefBx = []; arCoefBy = [] + + phaseIsVar = False + phasePrev = None + #print('Setting up tabulated magnetic field') + #print('Starting to read-in', nRows, 'files') + + for i in range(nRows): + curLine = lines[i] + curLineParts = curLine.split(strSep) + curLenLineParts = len(curLineParts) + if(curLenLineParts >= 4): + curPhaseMode = curLineParts[1] + if(curPhaseMode != _ph_mode): continue + + arGaps.append(float(curLineParts[0])) + + curPhase = float(curLineParts[2]) + if((phasePrev is not None) and (curPhase != phasePrev)): phaseIsVar = True + arPhases.append(curPhase) + phasePrev = curPhase + + #curFileName = curLineParts[3] + curFileName = curLineParts[3].strip() #MR13012017 + #print(curFileName) + + if(len(curFileName) > 0): + curFilePath = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, curFileName) + #print(curFilePath) + curFldCnt = srwl_uti_read_mag_fld_3d(curFilePath, '#') + arMagFld3D.append(curFldCnt.arMagFld[0]) + arXc.append(curFldCnt.arXc[0]) + arYc.append(curFldCnt.arYc[0]) + arZc.append(curFldCnt.arZc[0] + _zc) + + if(curLenLineParts >= 6): + arCoefBx.append(float(curLineParts[4])) + arCoefBy.append(float(curLineParts[5])) + f.close() + #print('Done reading-in magnetic field files') + + fldCnt = SRWLMagFldC(arMagFld3D, array('d', arXc), array('d', arYc), array('d', arZc)) + nElem = len(arMagFld3D) + if((nElem != len(arGaps)) or (nElem != len(arPhases))): + raise Exception('Inconsistent magnetic field data summary file') + + fldCnt.arPar1 = array('d', arGaps) + fldCnt.arPar2 = array('d', arPhases) + if(len(arCoefBx) == nElem): fldCnt.arPar3 = array('d', arCoefBx) + if(len(arCoefBy) == nElem): fldCnt.arPar4 = array('d', arCoefBy) + + #print(' Gaps:', fldCnt.arPar1) + #print(' Phase Mode:', _ph_mode) + #print(' Phases:', fldCnt.arPar2) + #if(phaseIsVar is True): print(' Phase is variable') + #else: print(' Phase is constant') + + fldCntRes = SRWLMagFldC(arMagFld3D[0], arXc[0], arYc[0], arZc[0]) + + numDims = 1 + if(phaseIsVar): numDims += 1 + precPar = [numDims, _gap, _phase, _interp_ord] + #precPar = [1, _gap, _phase, _interp_ord] + self.mag = srwl.CalcMagnField(fldCntRes, fldCnt, precPar) + + if((_dg_by_len != 0.) or (_y0 != 0.) or (_yp != 0.)): + self.mag.arMagFld[0] = srwl_und_fld_1d_mis(self.mag.arMagFld[0], _per, _dg_by_len, _c1, _c2, 0.001*_gap, _a, _y0, _yp) + + return self.mag + + #------------------------------------------------------------------------ + def set_und_tab(self, _gap, _ph_mode='p1', _phase=0., _zc=0., _interp_ord=1, _meas_or_calc='m', _per=0.02, _c1=0, _c2=0, _a=0, _dg_by_len=0, _y0=0, _yp=0): + #def set_und_tab_faster(self, _gap, _ph_mode='p1', _phase=0., _zc=0., _interp_ord=1, _meas_or_calc='m', _per=0.02, _c1=0, _c2=0, _a=0, _dg_by_len=0, _y0=0, _yp=0): + """Setup magnetic field container with magnetic measurements or calculation data interpolated for given gap and phase. Faster version, reading only requiired field files. + :param _gap: magnetic gap [mm] for which the field should be set up + :param _ph_mode: type of phase (shift of magnet arrays) motion + :param _phase: shift of magnet arrays [mm] for which the field should be set up + :param _zc: center position [m] + :param _interp_ord: order of interpolation: 1- (bi-)linear, 2- (bi-)quadratic, 3- (bi-)cubic + :param _meas_or_calc: use magnetic measurements ('m') or calculation ('c') data + :param _per: undulator period [m] + :param _c1: constant defining (approximate) undulator field dependence on gap (i.e. c1 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _c2: constant defining (approximate) undulator field dependence on gap (i.e. c2 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _a: constant defining (approximate) undulator field dependence on vertical position (i.e. a in cosh(2*Pi*a*y/per) + :param _dg_by_len: gap taper (exit minus entrance) divided by undulator length + :param _y0: vertical electron position in the center of undulator relative to undulator median plane [m] + :param _dydz: vertical electron angle in the center of undulator relative to undulator median plane [rad] + """ + + fPathSum = '' + if(_meas_or_calc == 'm'): + if(hasattr(self, 'dir_magn_meas') and hasattr(self, 'fn_magn_meas_sum')): + fPathSum = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, self.fn_magn_meas_sum) + else: raise Exception('No magnetic measurements data are supplied') + elif(_meas_or_calc == 'c'): + raise Exception('No magnetic calculation data are supplied') + + f = open(fPathSum, 'r') + lines = f.readlines() #read-in all lines + nRows = len(lines) + + strSep = '\t' + arGaps = []; arPhases = []; arFieldFileNames = []; arIndReqFiles = [] + #arXc = []; arYc = []; arZc = [] + arCoefBx = []; arCoefBy = [] + + phaseIsVar = False + phasePrev = None + #print('Setting up tabulated magnetic field') + + #Read-in summary file and setup aux. arrays + for i in range(nRows): + curLine = lines[i] + curLineParts = curLine.split(strSep) + curLenLineParts = len(curLineParts) + if(curLenLineParts >= 4): + curPhaseMode = curLineParts[1] + if(curPhaseMode != _ph_mode): continue + + curFileName = curLineParts[3].strip() #MR13012017 + #print(curFileName) + + if(len(curFileName) > 0): + arFieldFileNames.append(curFileName) + + arGaps.append(float(curLineParts[0])) + + curPhase = float(curLineParts[2]) + if((phasePrev is not None) and (curPhase != phasePrev)): phaseIsVar = True + arPhases.append(curPhase) + phasePrev = curPhase + + arIndReqFiles.append(-1) #Array to be filled-out from C + + if(curLenLineParts >= 6): + arCoefBx.append(float(curLineParts[4])) + arCoefBy.append(float(curLineParts[5])) + f.close() + + numDims = 1 + if(phaseIsVar): numDims += 1 + meshIsRect = 0 + precPar = [numDims, _gap, _phase, _interp_ord, meshIsRect] #NOTE: these values can be modified by srwl.UtiUndFindMagFldInterpInds + + #print(precPar) + nIndReq = srwl.UtiUndFindMagFldInterpInds(arIndReqFiles, arGaps, arPhases, precPar) #to implement + #print(arIndReqFiles) + + if((nIndReq <= 0) or (nIndReq > nRows)): + raise Exception('Inconsistent magnetic field data summary file') + + arResMagFld3D = []; + arResGaps = []; arResPhases = []; + arResXc = []; arResYc = []; arResZc = [] + arResCoefBx = []; arResCoefBy = [] + for j in range(nIndReq): + curInd = arIndReqFiles[j] + + curFileName = arFieldFileNames[curInd] + curFilePath = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, curFileName) + #print(curFilePath) + + curFldCnt = srwl_uti_read_mag_fld_3d(curFilePath, '#') + if(curFldCnt is not None): + arResMagFld3D.append(curFldCnt.arMagFld[0]) + arResXc.append(curFldCnt.arXc[0]) + arResYc.append(curFldCnt.arYc[0]) + arResZc.append(curFldCnt.arZc[0] + _zc) + + arResGaps.append(arGaps[curInd]) + arResPhases.append(arPhases[curInd]) + + if(len(arCoefBx) > curInd): arResCoefBx.append(arCoefBx[curInd]) + if(len(arCoefBy) > curInd): arResCoefBy.append(arCoefBy[curInd]) + + fldResCnt = SRWLMagFldC(arResMagFld3D, array('d', arResXc), array('d', arResYc), array('d', arResZc)) + #nElem = len(arMagFld3D) + #if((nElem != len(arGaps)) or (nElem != len(arPhases))): + # raise Exception('Inconsistent magnetic field data summary file') + + fldResCnt.arPar1 = array('d', arResGaps) + fldResCnt.arPar2 = array('d', arResPhases) + if(len(arResCoefBx) == nIndReq): fldResCnt.arPar3 = array('d', arResCoefBx) + if(len(arResCoefBy) == nIndReq): fldResCnt.arPar4 = array('d', arResCoefBy) + + #print(' Gaps:', fldCnt.arPar1) + #print(' Phase Mode:', _ph_mode) + #print(' Phases:', fldCnt.arPar2) + #if(phaseIsVar is True): print(' Phase is variable') + #else: print(' Phase is constant') + + #fldCntFinRes = SRWLMagFldC(arResMagFld3D[0], arResXc[0], arResYc[0], arResZc[0]) + fldCntFinRes = SRWLMagFldC(copy(arResMagFld3D[0]), arResXc[0], arResYc[0], arResZc[0]) + + precPar.append(1) #this means that search for necessary subset of indexes should not be done, i.e. the field container is assumed to include only the fields necessary for the interpolaton + #print(precPar) + + self.mag = srwl.CalcMagnField(fldCntFinRes, fldResCnt, precPar) + + if((_dg_by_len != 0.) or (_y0 != 0.) or (_yp != 0.)): + self.mag.arMagFld[0] = srwl_und_fld_1d_mis(self.mag.arMagFld[0], _per, _dg_by_len, _c1, _c2, 0.001*_gap, _a, _y0, _yp) + + return self.mag + + #------------------------------------------------------------------------ + def set_und_per_from_tab(self, _rel_ac_thr=0.05, _max_nh=5, _max_per=0.1): + """Setup periodic Magnetic Field from Tabulated one + :param _rel_ac_thr: relative accuracy threshold + :param _max_nh: max. number of harmonics to create + :param _max_per: max. period length to consider + """ + + sErMes = 'Magnetic Field is not defined' + if(self.mag is None): Exception(sErMes) + if(isinstance(self.mag, SRWLMagFldC) == False): raise Exception(sErMes) + + arHarm = [] + for i in range(_max_nh): arHarm.append(SRWLMagFldH()) + + self.mag_approx = SRWLMagFldC(SRWLMagFldU(arHarm)) + srwl.UtiUndFromMagFldTab(self.mag_approx, self.mag, [_rel_ac_thr, _max_nh, _max_per]) + return self.mag_approx + + #------------------------------------------------------------------------ + def set_mag_tab(self, _fpath, _zc=0, _interp_ord=1): + """Setup magnetic field container with tabulated magnetic field data + :param _fpath: path to magnetic field data file + :param _zc: center position[m] + :param _interp_ord: order of interpolation: 1- (bi-)linear, 2- (bi-)quadratic, 3- (bi-)cubic + """ + + fpath = _fpath.strip() #MR13012017 #OC13012017 + + #if(os.path.exists(_fpath) == False): + if(os.path.exists(fpath) == False): #OC13012017 + raise Exception('No magnetic field data are supplied') + + #self.mag = srwl_uti_read_mag_fld_3d(_fpath) + self.mag = srwl_uti_read_mag_fld_3d(fpath) #OC13012017 + self.mag.arZc[0] += _zc #? + + #print('mag was set up in srwl_bl') + return self.mag + + #------------------------------------------------------------------------ + def set_gsn_beam(self, _x=0, _y=0, _z=0, _xp=0, _yp=0, _avgPhotEn=1, _pulseEn=1, _repRate=1, _polar=1, + _sigX=10e-06, _sigY=10e-06, _sigT=1e-15, _mx=0, _my=0, _presCA='c', _presFT='t'): + """Setup Gaussian beam source + :param _x: average horizontal coordinates of waist [m] + :param _y: average vertical coordinates of waist [m] + :param _z: average longitudinal coordinate of waist [m] + :param _xp: average horizontal angle at waist [rad] + :param _yp: average verical angle at waist [rad] + :param _avgPhotEn: average photon energy [eV] + :param _pulseEn: energy per pulse [J] + :param _repRate: rep. rate [Hz] + :param _polar: polarization 1- lin. hor., 2- lin. vert., 3- lin. 45 deg., 4- lin.135 deg., 5- circ. right, 6- circ. left + :param _sigX: RMS beam size vs horizontal position [m] at waist (for intensity) + :param _sigY: RMS beam size vs vertical position [m] at waist (for intensity) + :param _sigT: RMS pulse duration [s] (for intensity) + :param _mx: transverse Gauss-Hermite mode order in horizontal direction + :param _my: transverse Gauss-Hermite mode order in vertical direction + :param _presCA: treat _sigX, _sigY as sizes in [m] in coordinate representation (_presCA="c") or as angular divergences in [rad] in angular representation (_presCA="a") + :param _presFT: treat _sigT as pulse duration in [s] in time domain/representation (_presFT="t") or as bandwidth in [eV] in frequency domain/representation (_presFT="f") + """ + + if(self.gsnBeam is not None): del self.gsnBeam + + sigX = _sigX + sigY = _sigY + if(_presCA == 'a'): + convConstCA = _LightSp*_PlanckConst_eVs/(4*_Pi*_avgPhotEn) + sigX = convConstCA/sigX + sigY = convConstCA/sigY + + sigT = _sigT + if(_presFT == 'f'): + convConstFT = _PlanckConst_eVs/(4*_Pi) + sigT = convConstFT/sigT + + self.gsnBeam = SRWLGsnBm(_x, _y, _z, _xp, _yp, _avgPhotEn, _pulseEn, _repRate, _polar, sigX, sigY, sigT, _mx, _my) + return self.gsnBeam + + #------------------------------------------------------------------------ + def set_pt_src(self, _x=0, _y=0, _z=0, _flux=1, _unitFlux=1, _polar=1): + """Setup Gaussian beam source + :param _x: average horizontal coordinates of waist [m] + :param _y: average vertical coordinates of waist [m] + :param _z: average longitudinal coordinate of waist [m] + :param _flux: spectral flux + :param _unitFlux: spectral flux units: 1- ph/s/.1%bw, 2- W/eV + :param _polar: polarization 1- lin. hor., 2- lin. vert., 3- lin. 45 deg., 4- lin.135 deg., 5- circ. right, 6- circ. left, 7- radial + """ + + if(hasattr(self, 'ptSrc')): + if(self.ptSrc is not None): del self.ptSrc + + self.ptSrc = SRWLPtSrc(_x, _y, _z, _flux, _unitFlux, _polar) + return self.ptSrc + + #------------------------------------------------------------------------ + def set_optics(self, _op, _v=None): #OC28042018 + #def set_optics(self, _op): + """Setup optical element container + :param _op: optical element container (SRWLOptC instance) + :param _v: additional propagation-related options + """ + + #if((_op is None) or (isinstance(_op, SRWLOptC) == False)): + if((_op is None) or (not isinstance(_op, SRWLOptC))): + raise Exception('Incorrect optics container (SRWLOptC) structure') + + #print(_v) + if(_v is not None): #OC28042018 + if(_v.op_dp != 0): + _op.append_drift(_v.op_dp) + + if(self.optics is not None): del self.optics + self.optics = _op + + #------------------------------------------------------------------------ + def set_detector(self, _x=0, _rx=0, _nx=0, _dx=0, _y=0, _ry=0, _ny=0, _dy=0, _ord=1, _fname=''): + """Setup detector + :param _x: horizontal center position of active area [m] + :param _rx: horizontal size of active area [m] + :param _nx: number of pixels in horizontal direction + :param _dx: horizontal pixel size [m] + :param _y: vertical center position of active area [m] + :param _ry: vertical size of active area [m] + :param _ny: number of pixels in vertical direction + :param _dy: vertical pixel size [m] + :param _ord: interpolation order (i.e. order of polynomials to be used at 2D interpolation) + :param _fname: file name with detector spectral efficiency data + """ + + if((_rx <= 0) and (_nx <= 0) and (_ry <= 0) and (_ny <= 0)): + raise Exception('Incorrect detector parameters') + + detSpecEff = 1 + eStartDetSpecEff = 0 + eFinDetSpecEff = 0 + #if(len(_fname) > 0): + #Read-in detector spectral efficiency + #detSpecEff = ... + + xHalfRangeDet = 0.5*_rx + yHalfRangeDet = 0.5*_ry + #self.detector = SRWLDet( + return SRWLDet( + _xStart = _x - xHalfRangeDet, _xFin = _x + xHalfRangeDet, _nx = _nx, + _yStart = _y - yHalfRangeDet, _yFin = _y + yHalfRangeDet, _ny = _ny, + _dx = _dx, _dy = _dy, + _spec_eff = detSpecEff, _eStart = eStartDetSpecEff, _eFin = eFinDetSpecEff) + + #------------------------------------------------------------------------ + def calc_el_trj(self, _ctst, _ctfi, _np=50000, _mag_type=1, _fname=''): + """Calculates electron trajectory + :param _ctst: initial time (ct) for trajectory calculation + :param _ctfi: final time (ct) for trajectory calculation + :param _np: number of points for trajectory calculation + :param _mag_type: "type" of magnetic field to use: + 1- "Approximate", referenced by self.mag_approx; + 2- "Accurate" (tabulated), referenced by self.mag; + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :return: trajectory structure + """ + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + + if(_mag_type == 1): + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + elif(_mag_type == 2): + if(self.mag is None): Exception('Magnetic Field is not defined') + else: Exception('Incorrect Magnetic Field type identificator') + + magToUse = self.mag_approx + if(_mag_type == 2): + magToUse = self.mag + #print('Using tabulated magnetic field...') + + partTraj = SRWLPrtTrj() + partTraj.partInitCond = self.eBeam.partStatMom1 + partTraj.allocate(_np, True) + partTraj.ctStart = _ctst #Start Time (ct) for the calculation + partTraj.ctEnd = _ctfi + + arPrecPar = [1] #General Precision parameters for Trajectory calculation: + #[0]: integration method No: + #1- fourth-order Runge-Kutta (precision is driven by number of points) + #2- fifth-order Runge-Kutta + #[1],[2],[3],[4],[5]: absolute precision values for X[m],X'[rad],Y[m],Y'[rad],Z[m] (yet to be tested!!) - to be taken into account only for R-K fifth order or higher + #[6]: tolerance (default = 1) for R-K fifth order or higher + #[7]: max. number of auto-steps for R-K fifth order or higher (default = 5000) + + print('Electron trajectory calculation ... ', end='') + #print('Magnetic Field Object:', magToUse) + srwl.CalcPartTraj(partTraj, magToUse, arPrecPar) + print('completed') + + if(len(_fname) > 0): + print('Saving trajectory data to a file ... ', end='') + partTraj.save_ascii(_fname) + print('completed') + + return partTraj + + #------------------------------------------------------------------------ + def calc_int_from_wfr(self, _wfr, _pol=6, _int_type=0, _det=None, _fname='', _pr=True): #OC06042018 + """Calculates intensity from electric field and saving it to a file + :param _wfr: electric field wavefront (instance of SRWLWfr) + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _int_type: "type" of a characteristic to be extracted: + -1- No Intensity / Electric Field components extraction is necessary (only Wavefront will be calculated) + 0- "Single-Electron" Intensity; + 1- "Multi-Electron" Intensity; + 2- "Single-Electron" Flux; + 3- "Multi-Electron" Flux; + 4- "Single-Electron" Radiation Phase; + 5- Re(E): Real part of Single-Electron Electric Field; + 6- Im(E): Imaginary part of Single-Electron Electric Field; + 7- "Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence); + :param _det: detector (instance of SRWLDet) + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :param _pr: switch specifying if printing tracing the execution should be done or not + :return: 1D array with (C-aligned) resulting intensity data + """ + + if _pr: + print('Extracting intensity and saving it to a file ... ', end='') + t0 = time.time(); + + sNumTypeInt = 'f' + if(_int_type == 4): sNumTypeInt = 'd' #Phase? + + resMeshI = deepcopy(_wfr.mesh) + + depType = resMeshI.get_dep_type() + if(depType < 0): Exception('Incorrect numbers of points in the mesh structure') + + arI = array(sNumTypeInt, [0]*resMeshI.ne*resMeshI.nx*resMeshI.ny) + srwl.CalcIntFromElecField(arI, _wfr, _pol, _int_type, depType, resMeshI.eStart, resMeshI.xStart, resMeshI.yStart) + + if(_det is not None): + resStkDet = _det.treat_int(arI, resMeshI) + arI = resStkDet.arS + resMeshI = resStkDet.mesh + + if(len(_fname) > 0): srwl_uti_save_intens_ascii(arI, resMeshI, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + if _pr: print('completed (lasted', round(time.time() - t0, 2), 's)') + + return arI, resMeshI + + #------------------------------------------------------------------------ + #def calc_sr_se(self, _mesh, _samp_fact=-1, _meth=2, _rel_prec=0.01, _pol=6, _int_type=0, _mag_type=1, _fname=''): + #def calc_sr_se(self, _mesh, _samp_fact=-1, _meth=2, _rel_prec=0.01, _pol=6, _int_type=0, _mag_type=1, _fname='', _det=None): #OC06122016 + def calc_sr_se(self, _mesh, _samp_fact=-1, _meth=2, _rel_prec=0.01, _pol=6, _int_type=0, _mag_type=1, _fname='', _det=None, _zi=0, _zf=0, _pr=True): #OC27122016 + """Calculates single-electron intensity + :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) + :param _samp_fact: sampling factor for adjusting nx, ny (effective if > 0) + :param _meth: SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" + :param _rel_prec: relative precision + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _int_type: "type" of a characteristic to be extracted: + -1- No Intensity / Electric Field components extraction is necessary (only Wavefront will be calculated) + 0- "Single-Electron" Intensity; + 1- "Multi-Electron" Intensity; + 2- "Single-Electron" Flux; + 3- "Multi-Electron" Flux; + 4- "Single-Electron" Radiation Phase; + 5- Re(E): Real part of Single-Electron Electric Field; + 6- Im(E): Imaginary part of Single-Electron Electric Field; + 7- "Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence); + :param _mag_type: "type" of magnetic field to use: + 1- "Approximate", referenced by self.mag_approx; + 2- "Accurate" (tabulated), referenced by self.mag; + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :param _det: detector (instance of SRWLDet) + :param _zi: initial lonngitudinal position [m] of electron trajectory for SR calculation + :param _zf: final lonngitudinal position [m] of electron trajectory for SR calculation + :return: resulting wavefront (instance of SRWLWfr) and 1D array with (C-aligned) intensity data + """ + + #if((_mesh is None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #depType = -1 + #if((_mesh.ne >= 1) and (_mesh.nx == 1) and (_mesh.ny == 1)): depType = 0 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 1 + #elif((_mesh.ne == 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 2 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 3 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 4 + #elif((_mesh.ne > 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 5 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 6 + + #depType = _mesh.get_dep_type() #OC06042018 + #if(depType < 0): Exception('Incorrect numbers of points in the mesh structure') + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + + #print('In the beginning of calc_sr_se, mag_approx:', self.mag_approx) + + if(_mag_type == 1): + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + elif(_mag_type == 2): + if(self.mag is None): Exception('Magnetic Field is not defined') + else: Exception('Incorrect Magnetic Field type identificator') + + magToUse = self.mag_approx + if(_mag_type == 2): + magToUse = self.mag + #print('Using tabulated magnetic field...') + + wfr = SRWLWfr() + wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.mesh = deepcopy(_mesh) + wfr.partBeam = self.eBeam + + #zStartInteg = 0 #longitudinal position to start integration (effective if < zEndInteg) + #zEndInteg = 0 #longitudinal position to finish integration (effective if > zStartInteg) + zStartInteg = _zi #longitudinal position to start integration (effective if < zEndInteg) + zEndInteg = _zf #longitudinal position to finish integration (effective if > zStartInteg) + npTraj = 50000 #Number of points for trajectory calculation + useTermin = 1 #Use "terminating terms" (i.e. asymptotic expansions at zStartInteg and zEndInteg) or not (1 or 0 respectively) + arPrecPar = [_meth, _rel_prec, zStartInteg, zEndInteg, npTraj, useTermin, _samp_fact] + + #print('calc_sr_se: magToUse=', magToUse) + #print('calc_sr_se: magToUse.arMagFld[0]=', magToUse.arMagFld[0]) + + if _pr: + print('Single-electron SR calculation ... ', end='') + t0 = time.time(); + + #DEBUG + #print(' e-beam z=', wfr.partBeam.partStatMom1.z) + #print('Eel=', wfr.partBeam.partStatMom1.get_E(), ' GeV') + #print('xe=', wfr.partBeam.partStatMom1.x, ' xpe=', wfr.partBeam.partStatMom1.xp, ' ye=', wfr.partBeam.partStatMom1.y, ' ype=', wfr.partBeam.partStatMom1.yp) + #print('nx=', wfr.mesh.nx, ' xStart=', wfr.mesh.xStart, ' xFin=', wfr.mesh.xFin) + #print('ny=', wfr.mesh.ny, ' yStart=', wfr.mesh.yStart, ' yFin=', wfr.mesh.yFin) + #END DEBUG + + srwl.CalcElecFieldSR(wfr, 0, magToUse, arPrecPar) #calculate SR + if _pr: print('completed (lasted', round(time.time() - t0, 2), 's)') + + arI = None + resMeshI = None + if(_int_type >= 0): + arI, resMeshI = self.calc_int_from_wfr(wfr, _pol, _int_type, _det, _fname) + + #print('Extracting intensity and saving it to a file ... ', end='') + #t0 = time.time(); + #sNumTypeInt = 'f' + #if(_int_type == 4): sNumTypeInt = 'd' #Phase? + + #resMeshI = deepcopy(wfr.mesh) + #arI = array(sNumTypeInt, [0]*resMeshI.ne*resMeshI.nx*resMeshI.ny) + #srwl.CalcIntFromElecField(arI, wfr, _pol, _int_type, depType, resMeshI.eStart, resMeshI.xStart, resMeshI.yStart) + + #if(_det is not None): #OC06122016 + # resStkDet = _det.treat_int(arI, resMeshI) #OC11012017 + # arI = resStkDet.arS + # resMeshI = resStkDet.mesh + + #if(len(_fname) > 0): srwl_uti_save_intens_ascii(arI, resMeshI, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + #print('completed (lasted', round(time.time() - t0, 6), 's)') + + return wfr, arI, resMeshI #OC06122016 + + #------------------------------------------------------------------------ + #def calc_rad_gsn(self, _mesh, _samp_fact=-1, _pol=6, _int_type=0, _presFT='f', _unitE=2, _fname=''): + def calc_rad_gsn(self, _mesh, _samp_fact=-1, _pol=6, _int_type=0, _presFT='f', _unitE=2, _fname='', _det=None, _pr=True): #OC06122016 + """Calculates Gaussian beam wavefront (electric field) and intensity + :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) + :param _samp_fact: sampling factor for adjusting nx, ny (effective if > 0) + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _int_type: "type" of a characteristic to be extracted: + -1- No Intensity / Electric Field components extraction is necessary (only Wavefront will be calculated) + 0- "Single-Electron" / Coherent Beam Intensity; + 1- "Multi-Electron" / Partially-Coherent Beam Intensity; + 2- "Single-Electron" / Coherent Beam Flux; + 3- "Multi-Electron" / Partially-Coherent Beam Flux; + 4- "Single-Electron" / Coherent Beam Radiation Phase; + 5- Re(E): Real part of Single-Electron / Coherent Beam Electric Field; + 6- Im(E): Imaginary part of Single-Electron / Coherent Beam Electric Field; + 7- "Single-Electron" / Coherent Beam Intensity, integrated over Time or Photon Energy (i.e. Fluence); + :param _presFT: calculate electric field (and intensity) in time domain/representation (="t") or in frequency domain/representation (="f") + :param _unitE: #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :return: 1D array with (C-aligned) resulting intensity data + """ + + #if((_mesh is None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #depType = -1 + #if((_mesh.ne >= 1) and (_mesh.nx == 1) and (_mesh.ny == 1)): depType = 0 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 1 + #elif((_mesh.ne == 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 2 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 3 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 4 + #elif((_mesh.ne > 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 5 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 6 + + #depType = _mesh.get_dep_type() #OC11102017 + #if(depType < 0): Exception('Incorrect numbers of points in the mesh structure') + + wfr = SRWLWfr() + wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.mesh = deepcopy(_mesh) + + wfr.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + if(_presFT == "t"): wfr.presFT = 1 + + wfr.unitElFld = _unitE; + + locGsnBeam = copy(self.gsnBeam) #OC16102017 + if(self.eBeam is not None): + locGsnBeam.x += self.eBeam.partStatMom1.x + locGsnBeam.y += self.eBeam.partStatMom1.y + locGsnBeam.z = self.eBeam.partStatMom1.z #? + locGsnBeam.xp += self.eBeam.partStatMom1.xp + locGsnBeam.yp += self.eBeam.partStatMom1.yp + + #wfr.partBeam.partStatMom1.x = self.gsnBeam.x #Some information about the source in the Wavefront structure + #wfr.partBeam.partStatMom1.y = self.gsnBeam.y + #wfr.partBeam.partStatMom1.z = self.gsnBeam.z + #wfr.partBeam.partStatMom1.xp = self.gsnBeam.xp + #wfr.partBeam.partStatMom1.yp = self.gsnBeam.yp + #OC16102017 + wfr.partBeam.partStatMom1.x = locGsnBeam.x #Some information about the source in the Wavefront structure + wfr.partBeam.partStatMom1.y = locGsnBeam.y + wfr.partBeam.partStatMom1.z = locGsnBeam.z + wfr.partBeam.partStatMom1.xp = locGsnBeam.xp + wfr.partBeam.partStatMom1.yp = locGsnBeam.yp + + if(self.eBeam is not None): #OC16102017 + #print('Debug: 2nd order stat moments of incoherent beam:') + for i in range(len(wfr.partBeam.arStatMom2)): + wfr.partBeam.arStatMom2[i] = self.eBeam.arStatMom2[i] + #print(i, wfr.partBeam.arStatMom2[i]) + + if _pr: + print('Gaussian beam electric field calculation ... ', end='') + t0 = time.time(); + + #srwl.CalcElecFieldGaussian(wfr, self.gsnBeam, [_samp_fact]) + srwl.CalcElecFieldGaussian(wfr, locGsnBeam, [_samp_fact]) #OC16102017 + if _pr: print('completed (lasted', round(time.time() - t0, 2), 's)') + + arI = None + resMeshI = None + if(_int_type >= 0): + arI, resMeshI = self.calc_int_from_wfr(wfr, _pol, _int_type, _det, _fname) + + #print('Extracting intensity and saving it to a file ... ', end='') + #t0 = time.time(); + #sNumTypeInt = 'f' + #if(_int_type == 4): sNumTypeInt = 'd' + + #resMeshI = deepcopy(wfr.mesh) + #arI = array(sNumTypeInt, [0]*resMeshI.ne*resMeshI.nx*resMeshI.ny) + #srwl.CalcIntFromElecField(arI, wfr, _pol, _int_type, depType, resMeshI.eStart, resMeshI.xStart, resMeshI.yStart) + + #if(_det is not None): #OC06122016 + # resStkDet = _det.treat_int(arI, resMeshI) #OC11012017 + # arI = resStkDet.arS + # resMeshI = resStkDet.mesh + + #if(len(_fname) > 0): srwl_uti_save_intens_ascii(arI, resMeshI, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + #print('completed (lasted', round(time.time() - t0, 6), 's)') + + return wfr, arI, resMeshI #OC06122016 + + #------------------------------------------------------------------------ + def calc_rad_pt_src(self, _mesh, _samp_fact=-1, _pol=6, _int_type=0, _presFT='f', _unitE=2, _fname='', _det=None, _pr=True): #OC11102017 + """Calculates Spherical Wave electric field and intensity + :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) + :param _samp_fact: sampling factor for adjusting nx, ny (effective if > 0) + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _int_type: "type" of a characteristic to be extracted: + -1- No Intensity / Electric Field components extraction is necessary (only Wavefront will be calculated) + 0- "Single-Electron" / Coherent Beam Intensity; + 1- "Multi-Electron" / Partially-Coherent Beam Intensity; + 2- "Single-Electron" / Coherent Beam Flux; + 3- "Multi-Electron" / Partially-Coherent Beam Flux; + 4- "Single-Electron" / Coherent Beam Radiation Phase; + 5- Re(E): Real part of Single-Electron / Coherent Beam Electric Field; + 6- Im(E): Imaginary part of Single-Electron / Coherent Beam Electric Field; + 7- "Single-Electron" / Coherent Beam Intensity, integrated over Time or Photon Energy (i.e. Fluence); + :param _presFT: calculate electric field (and intensity) in time domain/representation (="t") or in frequency domain/representation (="f") + :param _unitE: #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :return: 1D array with (C-aligned) resulting intensity data + """ + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #depType = -1 + #if((_mesh.ne >= 1) and (_mesh.nx == 1) and (_mesh.ny == 1)): depType = 0 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 1 + #elif((_mesh.ne == 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 2 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 3 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 4 + #elif((_mesh.ne > 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 5 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 6 + + #depType = _mesh.get_dep_type() + #if(depType < 0): Exception('Incorrect numbers of points in the mesh structure') + + wfr = SRWLWfr() + wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.mesh = deepcopy(_mesh) + + wfr.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + if(_presFT == "t"): wfr.presFT = 1 + + wfr.unitElFld = _unitE; + + locPtSrc = copy(self.ptSrc) #OC16102017 + if(self.eBeam is not None): + locPtSrc.x += self.eBeam.partStatMom1.x + locPtSrc.y += self.eBeam.partStatMom1.y + locPtSrc.z = self.eBeam.partStatMom1.z #? + + #wfr.partBeam.partStatMom1.x = self.ptSrc.x #Some information about the source in the Wavefront structure + #wfr.partBeam.partStatMom1.y = self.ptSrc.y + #wfr.partBeam.partStatMom1.z = self.ptSrc.z + #wfr.partBeam.partStatMom1.xp = 0 + #wfr.partBeam.partStatMom1.yp = 0 + #OC16102017 + wfr.partBeam.partStatMom1.x = locPtSrc.x #Some information about the source in the Wavefront structure + wfr.partBeam.partStatMom1.y = locPtSrc.y + wfr.partBeam.partStatMom1.z = locPtSrc.z + wfr.partBeam.partStatMom1.xp = 0. + wfr.partBeam.partStatMom1.yp = 0. + + if(self.eBeam is not None): #OC16102017 + for i in range(len(wfr.partBeam.arStatMom2)): + wfr.partBeam.arStatMom2[i] = self.eBeam.arStatMom2[i] + + if _pr: + print('Spherical wave electric field calculation ... ', end='') + t0 = time.time(); + + #srwl.CalcElecFieldPointSrc(wfr, self.ptSrc, [_samp_fact]) + srwl.CalcElecFieldPointSrc(wfr, locPtSrc, [_samp_fact]) + if _pr: print('completed (lasted', round(time.time() - t0, 2), 's)') + + arI = None + resMeshI = None + if(_int_type >= 0): + arI, resMeshI = self.calc_int_from_wfr(wfr, _pol, _int_type, _det, _fname) + + #print('Extracting intensity and saving it to a file ... ', end='') + #t0 = time.time(); + #sNumTypeInt = 'f' + #if(_int_type == 4): sNumTypeInt = 'd' + + #resMeshI = deepcopy(wfr.mesh) + #arI = array(sNumTypeInt, [0]*resMeshI.ne*resMeshI.nx*resMeshI.ny) + #srwl.CalcIntFromElecField(arI, wfr, _pol, _int_type, depType, resMeshI.eStart, resMeshI.xStart, resMeshI.yStart) + + #if(_det is not None): #OC06122016 + # resStkDet = _det.treat_int(arI, resMeshI) #OC11012017 + # arI = resStkDet.arS + # resMeshI = resStkDet.mesh + + #if(len(_fname) > 0): srwl_uti_save_intens_ascii(arI, resMeshI, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2']) + #print('completed (lasted', round(time.time() - t0, 6), 's)') + + #print('wfr.mesh.eStart=', wfr.mesh.eStart, 'wfr.mesh.eFin=', wfr.mesh.eFin, 'wfr.mesh.ne=', wfr.mesh.ne) + #print('resMeshI.eStart=', resMeshI.eStart, 'resMeshI.eFin=', resMeshI.eFin, 'resMeshI.ne=', resMeshI.ne) + #print('wfr.mesh.xStart=', wfr.mesh.xStart, 'wfr.mesh.xFin=', wfr.mesh.xFin, 'wfr.mesh.nx=', wfr.mesh.nx) + #print('resMeshI.xStart=', resMeshI.xStart, 'resMeshI.xFin=', resMeshI.xFin, 'resMeshI.nx=', resMeshI.nx) + #print('wfr.mesh.yStart=', wfr.mesh.yStart, 'wfr.mesh.yFin=', wfr.mesh.yFin, 'wfr.mesh.ny=', wfr.mesh.ny) + #print('resMeshI.yStart=', resMeshI.yStart, 'resMeshI.yFin=', resMeshI.yFin, 'resMeshI.ny=', resMeshI.ny) + + return wfr, arI, resMeshI + + #------------------------------------------------------------------------ + def calc_ur_spec_me(self, _mesh, _harm_init=1, _harm_fin=15, _prec_long=1., _prec_azim=1., _type=1, _pol=6, _fname=''): + """Calculates multi-electron flux of undulator radiation (within fixed aperture of per unit surface), using approximate periodic magnetic field + :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) + :param _harm_init: initial UR spectral harmonic to be taken into account + :param _harm_fin: final UR spectral harmonic to be taken into account + :param _prec_long: longitudinal integration precision parameter + :param _prec_azim: azimuthal integration precision parameter + :param _type: calculate flux (=1) or flux per unit surface (=2) + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :return: 1D array with (C-aligned) resulting intensity data + """ + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #depType = -1 + #if((_mesh.ne >= 1) and (_mesh.nx == 1) and (_mesh.ny == 1)): depType = 0 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 1 + #elif((_mesh.ne == 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 2 + #elif((_mesh.ne == 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 3 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny == 1)): depType = 4 + #elif((_mesh.ne > 1) and (_mesh.nx == 1) and (_mesh.ny > 1)): depType = 5 + #elif((_mesh.ne > 1) and (_mesh.nx > 1) and (_mesh.ny > 1)): depType = 6 + + depType = _mesh.get_dep_type() #OC06042018 + if(depType < 0): Exception('Incorrect numbers of points in the mesh structure') + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + + stk = SRWLStokes() + stk.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #numbers of points vs photon energy, horizontal and vertical positions + stk.mesh = deepcopy(_mesh) + + #Precision Parampeters for Spectral Flux through a Slit: + arPrecPar = [_harm_init, _harm_fin, _prec_long, _prec_azim, _type] + + und = self.mag_approx.arMagFld[0] + if(isinstance(und, SRWLMagFldU) == False): raise Exception('Incorrect SRWLMagFldU (i.e. undulator) structure') + + eBeamAux = self.eBeam + zc = self.mag_approx.arZc[0] + if(zc != 0.): + #since the srwl.CalcStokesUR method assumes undulator located at zc = 0, + #we have to "move" observation plane and the longitudinal position at which e-beam parameters are defined + stk.mesh.zStart -= zc + eBeamAux = deepcopy(self.eBeam) + eBeamAux.drift(-zc) + + srwl.CalcStokesUR(stk, eBeamAux, und, arPrecPar) + #Consider treating detector here? + + arI = stk.to_int(_pol) + if(len(_fname) > 0): + sValName = 'Flux' + sValUnitName = 'ph/s/.1%bw' + if(_type == 2): + sValName = 'Intensity' + sValUnitName = 'ph/s/.1%bw/mm^2' + srwl_uti_save_intens_ascii(arI, stk.mesh, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', sValName], _arUnits=['eV', 'm', 'm', sValUnitName]) + return arI + + #------------------------------------------------------------------------ + #def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None): + def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None, _sr_samp_fact=-1, _det=None, _me_approx=0): #OC13042018 + """Calculates multi-electron flux of undulator radiation (within fixed aperture of per unit surface), using approximate periodic magnetic field + :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) + :param _meth: SR Electric Field calculation method to be used (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") + :param _rel_prec: relative precision for SR Electric Field calculation (usually 0.01 is OK, smaller the more accurate) + :param _n_part_tot: total number of "macro-electrons" to be used in the calculation + :param _n_part_avg_proc: number of "macro-electrons" to be used in calculation at each "slave" before sending Stokes data to "master" (effective if the calculation is run via MPI) + :param _n_save_per: periodicity of saving intermediate average Stokes data to file by master process + :param _type: calculate flux (=1) or flux per unit surface (=2) + :param _mag: magnetic field to be used for calculation of multi-e spectrum spectrum or intensity distribution: 1- approximate, 2- accurate + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _rand_meth: method for generation of pseudo-random numbers for e-beam phase-space integration: + 1- standard pseudo-random number generator + 2- Halton sequences + 3- LPtau sequences (to be implemented) + :param _fname: name of file to save the resulting data to (for the moment, in ASCII format) + :param _det: detector structure ensuring a given final mesh on which the calculated intensity (or other characteristic) will be interpolated + :param _me_approx: multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance + :return: 1D array with (C-aligned) resulting intensity data + """ + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + + mag2use = self.mag + if(_mag == 1): + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + mag2use = self.mag_approx + else: + if(self.mag is None): Exception('Accurate Magnetic Field is not defined') + + charMultiE = 0 #Calculate intensity (flux per unit surface by default) + if(_type == 1): charMultiE = 10 #Calculate flux + + #print(_fname) + stk = srwl_wfr_emit_prop_multi_e( + _e_beam = self.eBeam, _mag = mag2use, _mesh = _mesh, + _sr_meth = _meth, _sr_rel_prec = _rel_prec, + _n_part_tot = _n_part_tot, _n_part_avg_proc = _n_part_avg_proc, _n_save_per = _n_save_per, _rand_meth = _rand_meth, + #_file_path = _fname, _char = charMultiE) + _file_path = _fname, _sr_samp_fact = _sr_samp_fact, _char = charMultiE, _det = _det, _me_approx = _me_approx) #OC14042018 + #Consider treating detector here? + + arI = None + if(stk is not None): + arI = stk.to_int(_pol) + if(len(_fname) > 0): + sValName = 'Flux' + sValUnitName = 'ph/s/.1%bw' + if(_type == 2): + sValName = 'Intensity' + sValUnitName = 'ph/s/.1%bw/mm^2' + srwl_uti_save_intens_ascii(arI, stk.mesh, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', sValName], _arUnits=['eV', 'm', 'm', sValUnitName]) + return arI + + #------------------------------------------------------------------------ + def calc_pow_den(self, _mesh, _prec=1, _meth=1, _z_start=0., _z_fin=0., _mag_type=1, _fname=''): + """Calculates multi-electron flux of undulator radiation (within fixed aperture of per unit surface), using approximate periodic magnetic field + :param _mesh: mesh (grid) on which the power density has to be calculated (SRWLRadMesh instance) + :param _prec: precision factor for calculation of power density distribution + :param _meth: power density computation method (1- "near field", 2- "far field") + :param _z_start: initial longitudinal position along electron trajectory of power density distribution (effective if _s_start < _s_fin) + :param _z_fin: final longitudinal position along electron trajectory of power density distribution (effective if _s_start < _s_fin) + :param _mag_type: "type" of magnetic field to use: + 1- "Approximate", referenced by self.mag_approx; + 2- "Accurate" (tabulated), referenced by self.mag; + :param _fname: name of file to save the resulting data to + :return: 1D array with (C-aligned) resulting power density data + """ + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + + if(_mag_type == 1): + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + elif(_mag_type == 2): + if(self.mag is None): Exception('Magnetic Field is not defined') + else: Exception('Incorrect Magnetic Field type identificator') + + magToUse = self.mag_approx + if(_mag_type == 2): magToUse = self.mag + + arPrecPar = [_prec, _meth, _z_start, _z_fin, 20000] + + stkP = SRWLStokes() #for power density vs x and y + stkP.allocate(1, _mesh.nx, _mesh.ny) #numbers of points vs horizontal and vertical positions (photon energy is not taken into account) + stkP.mesh = deepcopy(_mesh) + srwl.CalcPowDenSR(stkP, self.eBeam, 0, magToUse, arPrecPar) #calculate SR + + if(len(_fname) > 0): + srwl_uti_save_intens_ascii(stkP.arS, _mesh, _fname, 0, + ['', 'Horizontal Position', 'Vertical Position', 'Power Density'], + _arUnits=['', 'm', 'm', 'W/mm^2']) + return stkP.arS #, arSx, arSy + + #------------------------------------------------------------------------ + def calc_und_oper_tab(self, _mesh, _pol=0, _hi=1, _hf=1, _meas_or_calc='m', _zc=0, _fname=''): + """Calculate undulator "operation table", i.e. dependence of gap (and phase) on photon energy (for a given polarization) + :param _mesh: mesh (grid) for which the operation table has to be calculated (SRWLRadMesh instance) + + """ + #['sm_pol', 'i', 6, 'polarization component to extract after calculation of multi-e flux or intensity: 0- Linear Horizontal, 1- Linear Vertical, 2- Linear 45 degrees, 3- Linear 135 degrees, 4- Circular Right, 5- Circular Left, 6- Total'], + + #print('Calculating undulator operation table') + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #print('_mesh.xStart=', _mesh.xStart, '_mesh.xFin=', _mesh.xFin) + + if(self.eBeam is None): Exception('Electron Beam structure is not defined') + + fPathSum = '' + if(_meas_or_calc == 'm'): + if(hasattr(self, 'dir_magn_meas') and hasattr(self, 'fn_magn_meas_sum')): + fPathSum = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, self.fn_magn_meas_sum) + else: raise Exception('No magnetic measurements data are supplied') + elif(_meas_or_calc == 'c'): + raise Exception('No magnetic calculation data are supplied') + + f = open(fPathSum, 'r') + lines = f.readlines() #read-in all lines + nRows = len(lines) + + strSep = '\t' + arGaps = []; arPhases = []; arMagFld3D = [] + arXc = []; arYc = []; arZc = [] + arCoefBx = []; arCoefBy = [] + + arHarmUR = []; arEnMaxIntSE = []; arEnMaxFluxEst = []; arMaxFlux = []; arPowTot = []; arPowInAp = [] + + phaseIsVar = False + phasePrev = None + #print('Setting up tabulated magnetic field') + + phModeReq = 'p1' + if((_pol == 2) or (_pol == 3)): #2- Linear 45 degrees, 3- Linear 135 degrees + phModeReq = 'p2' + + powNumX = 101; powNumY = 101 + #powNumX = 11; powNumY = 11 + nxPartIntegPowDens = 101; nyPartIntegPowDens = 101 + + relAcThrConv2Per = 0.05 + maxNumHarmConv2Per = 7 + maxPerConv2Per = 0.2 #to steer? + + curMeshF = deepcopy(_mesh) + curMeshF.nx = 1; curMeshF.ny = 1 + + curMeshI = deepcopy(_mesh) + + for i in range(nRows): + curLine = lines[i] + curLineParts = curLine.split(strSep) + curLenLineParts = len(curLineParts) + + curGap = None + curPhase = 0 + if(curLenLineParts >= 4): + curPhaseMode = curLineParts[1] + if(curPhaseMode != phModeReq): continue + + curGap = float(curLineParts[0]) + arGaps.append(curGap) + print('Gap:', curGap, 'mm') + + curPhase = float(curLineParts[2]) + if((phasePrev is not None) and (curPhase != phasePrev)): phaseIsVar = True + arPhases.append(curPhase) + phasePrev = curPhase + + #curFileName = curLineParts[3] + curFileName = curLineParts[3].strip() #MR13012017 + print('Magnetic Field Data File:', curFileName) + + curFldCnt = None + curZc = 0. + curCoefBx = 1. + curCoefBy = 1. + + if(len(curFileName) > 0): + curFilePath = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, curFileName) + curFldCnt = srwl_uti_read_mag_fld_3d(curFilePath, '#') + #arMagFld3D.append(curFldCnt.arMagFld[0]) + #arXc.append(curFldCnt.arXc[0]) + #arYc.append(curFldCnt.arYc[0]) + #arZc.append(curFldCnt.arZc[0] + _zc) + curFldCnt.arZc[0] += _zc + + if(curLenLineParts >= 6): + #arCoefBx.append(float(curLineParts[4])) + #arCoefBy.append(float(curLineParts[5])) + curCoefBx = float(curLineParts[4]) + curCoefBy = float(curLineParts[5]) + + if(((curCoefBx != 1.) or (curCoefBy != 1.)) and (curFldCnt is not None)): + curFld3D = curFldCnt.arMagFld[0] + iif = 0 + for iz in range(curFld3D.nz): + for iy in range(curFld3D.ny): + for ix in range(curFld3D.nx): + curFld3D.arBx[iif] *= curCoefBx + curFld3D.arBy[iif] *= curCoefBy + iif += 1 + + if(curFldCnt is not None): + + #Convert field to periodic + arHarm = [] + for iih in range(7): arHarm.append(SRWLMagFldH()) + undMagApprox = SRWLMagFldC(SRWLMagFldU(arHarm)) + + srwl.UtiUndFromMagFldTab(undMagApprox, curFldCnt, [relAcThrConv2Per, maxNumHarmConv2Per, maxPerConv2Per]) + + undApprox = undMagApprox.arMagFld[0] + elEnGeV = self.eBeam.partStatMom1.get_E('GeV') + e1Approx = undApprox.get_E1(elEnGeV, 'eV') + + #print('Undulator period:', undApprox.per, 'm') + #print('Electron energy:', elEnGeV, 'GeV') + #print('Undulator e1 =', e1Approx, 'eV') + + #Define spectral range and mesh for single-e & multi-e calculation + #curMesh = deepcopy(_mesh) + curMeshF.eStart = e1Approx*(_hi - 0.5) + curMeshF.eFin = e1Approx*(_hf + 0.5) + curMeshF.ne = 1000*(_hf - _hi + 1) + eStep = (curMeshF.eFin - curMeshF.eStart)/(curMeshF.ne - 1) + + #Calculate multi-e spectrum + stkSpF = SRWLStokes() #for spectral flux vs photon energy + stkSpF.allocate(curMeshF.ne, 1, 1) #numbers of points vs photon energy, horizontal and vertical positions + stkSpF.mesh = curMeshF + longPrecStkF = 1.5 #longitudinal integration precision parameter + azPrecStkF = 1.5 #azimuthal integration precision parameter + srwl.CalcStokesUR(stkSpF, self.eBeam, undMagApprox.arMagFld[0], [1, _hf+5, longPrecStkF, azPrecStkF, 1]) + + #Calculate single-e spectrum + wfrSp = SRWLWfr() + curMeshI.eStart = curMeshF.eStart + curMeshI.eFin = curMeshF.eFin + curMeshI.ne = curMeshF.ne + wfrSp.allocate(curMeshI.ne, 1, 1) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions (may be modified by the library!) + + wfrSp.mesh = curMeshI + wfrSp.partBeam = self.eBeam + + methSR = 1 #SR calculation method: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" + relPrecSR = 0.01 #relative precision + srwl.CalcElecFieldSR(wfrSp, 0, curFldCnt, [methSR, relPrecSR, 0, 0, 20000, 1, -1]) + + arSpecI = array('f', [0]*wfrSp.mesh.ne) #"flat" array to take 2D intensity data + srwl.CalcIntFromElecField(arSpecI, wfrSp, _pol, 0, 0, wfrSp.mesh.eStart, 0, 0) + + #Calculate multi-e power-density distribution + stkP = SRWLStokes() #for power density + stkP.allocate(1, powNumX, powNumY) #numbers of points vs horizontal and vertical positions (photon energy is not taken into account) + stkP.mesh.zStart = curMeshF.zStart #longitudinal position [m] at which power density has to be calculated + powHalfRangeX = 2.*curMeshF.zStart*undApprox.get_K()/self.eBeam.partStatMom1.gamma + powHalfRangeY = 2.*curMeshF.zStart/self.eBeam.partStatMom1.gamma + stkP.mesh.xStart = -powHalfRangeX #initial horizontal position [m] + stkP.mesh.xFin = powHalfRangeX #final horizontal position [m] + stkP.mesh.yStart = -powHalfRangeY #initial vertical position [m] + stkP.mesh.yFin = powHalfRangeY #final vertical position [m] + + #print('powHalfRangeX=', powHalfRangeX, 'powHalfRangeY=', powHalfRangeY) + #print('curMeshF.xStart=', curMeshF.xStart, 'curMeshF.xFin=', curMeshF.xFin) + #print('curMeshF.yStart=', curMeshF.yStart, 'curMeshF.yFin=', curMeshF.yFin) + #print('curMeshI.xStart=', curMeshI.xStart, 'curMeshI.xFin=', curMeshI.xFin) + #print('curMeshI.yStart=', curMeshI.yStart, 'curMeshI.yFin=', curMeshI.yFin) + + precFactPow = 1.5 #precision factor + methPow = 1 #power density computation method (1- "near field", 2- "far field") + srwl.CalcPowDenSR(stkP, self.eBeam, 0, curFldCnt, [precFactPow, methPow, 0, 0, 20000]) + powTot = uti_math.integ_ar_2d(stkP.arS, 1, [stkP.mesh.xStart, stkP.mesh.xFin, stkP.mesh.nx], [stkP.mesh.yStart, stkP.mesh.yFin, stkP.mesh.ny])*1.e+06 + + powInAp = uti_math.integ_ar_2d(stkP.arS, 1, [stkP.mesh.xStart, stkP.mesh.xFin, stkP.mesh.nx], [stkP.mesh.yStart, stkP.mesh.yFin, stkP.mesh.ny], + [curMeshF.xStart, curMeshF.xFin, nxPartIntegPowDens], [curMeshF.yStart, curMeshF.yFin, nyPartIntegPowDens])*1.e+06 + + print('Power ~total:', powTot, 'W') + print('Power within work aperture:', powInAp, 'W') + + #Determine energy shifts of different harmonics and required harmonic positions + #arEnShift = [] + for iHarmUR in range(_hi, _hf + 1, 1): + curEnStart = (iHarmUR - 0.5)*e1Approx + ieStartSearch = 0 + if((curEnStart > curMeshF.eStart) and (curEnStart <= curMeshF.eFin)): + ieStartSearch = int((curEnStart - curMeshF.eStart)/eStep + 1.e-10) + if(ieStartSearch < 0): ieStartSearch = 0 + + curEnEnd = (iHarmUR + 0.5)*e1Approx + ieEndSearch = 0 + if((curEnEnd > curMeshF.eStart) and (curEnEnd <= curMeshF.eFin)): + ieEndSearch = int((curEnEnd - curMeshF.eStart)/eStep + 1.e-10) + + if(ieEndSearch >= curMeshF.ne): ieEndSearch = curMeshF.ne - 1 + if(ieEndSearch < ieStartSearch): ieEndSearch = ieStartSearch + + curMaxFlux, iCurMaxFlux = uti_math.find_ar_max(stkSpF.arS, ieStartSearch, ieEndSearch) + enMaxFlux = curMeshF.eStart + eStep*iCurMaxFlux + enShift = enMaxFlux - e1Approx*iHarmUR + #arEnShift.append(enShift) + + curMaxIntSE, iCurMaxIntSE = uti_math.find_ar_max(arSpecI, ieStartSearch, ieEndSearch) + enMaxIntSE = curMeshI.eStart + eStep*iCurMaxIntSE + enMaxFluxEst = enMaxIntSE + enShift + + print('Harmonic Number:', iHarmUR) + print('Approx. Photon Energy for Max. Flux:', enMaxFlux, 'eV') + print('Estimated Photon Energy for Max. Flux:', enMaxFluxEst, 'eV') + print('Photon Energy (Red) Shift:', enShift, 'eV') + + #To improve: + #Treat different polarizations + #Determine polarization rate of required polarization + + #arResForHarm.append([iHarmUR, curGap, curMaxIntSE, enMaxFluxEst, curMaxFlux, powInAp]) + arHarmUR.append(iHarmUR) + arEnMaxIntSE.append(round(enMaxIntSE, 5)) + arEnMaxFluxEst.append(round(enMaxFluxEst, 5)) + arMaxFlux.append(round(curMaxFlux, 4)) + arPowTot.append(round(powTot, 4)) + arPowInAp.append(round(powInAp, 4)) + + f.close() + arResForHarm = [arHarmUR, arGaps, arPhases, arEnMaxIntSE, arEnMaxFluxEst, arMaxFlux, arPowTot, arPowInAp] + + if(len(_fname) > 0): + strHeader = '#harm, gap, phase, en_res, en_max, flux, pow_tot, pow_in_ap' + srwl_uti_write_data_cols(_fname, arResForHarm, '\t', strHeader) + + return arResForHarm + + #------------------------------------------------------------------------ + #def calc_wfr_prop(self, _wfr, _pres_ang=0, _pol=6, _int_type=0, _dep_type=3, _fname=''): + def calc_wfr_prop(self, _wfr, _pres_ang=0, _pol=6, _int_type=0, _dep_type=3, _fname='', _det=None): #OC06122016 + """Calculates single-electron (/ fully coherent) wavefront propagation + :param _wfr: wavefront (instance of SRWLWfr) to be propagated (and modified in place!) + :param _pres_ang: switch specifying whether the result of the propagation should be shown in angular presentation (1) or not (0) + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :param _int_type: "type" of a characteristic to be extracted: + -1- No Intensity / Electric Field components extraction is necessary (only Wavefront will be calculated) + 0- "Single-Electron" Intensity; + 1- "Multi-Electron" Intensity; + 2- "Single-Electron" Flux; + 3- "Multi-Electron" Flux; + 4- "Single-Electron" Radiation Phase; + 5- Re(E): Real part of Single-Electron Electric Field; + 6- Im(E): Imaginary part of Single-Electron Electric Field; + 7- "Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence); + :param _dep_type: "type" of dependence to be extracted: + 0- vs e (photon energy or time); + 1- vs x (horizontal position or angle); + 2- vs y (vertical position or angle); + 3- vs x&y (horizontal and vertical positions or angles); + 4- vs e&x (photon energy or time and horizontal position or angle); + 5- vs e&y (photon energy or time and vertical position or angle); + 6- vs e&x&y (photon energy or time, horizontal and vertical positions or angles); + + :param _fname: name of file to save the resulting data to + :return: 1D array with (C-aligned) resulting intensity data; it also modified _wfr in place + """ + + if((hasattr(self, 'optics') == False) or (isinstance(self.optics, SRWLOptC) == False)): + raise Exception('Incorrect optics container (SRWLOptC) structure') + if(isinstance(_wfr, SRWLWfr) == False): + raise Exception('Incorrect wavefront (SRWLWfr) structure') + + print('Propagation ... ', end='') + t0 = time.time(); + srwl.PropagElecField(_wfr, self.optics) + print('completed (lasted', round(time.time() - t0, 2), 's)') + + #print('_wfr.Rx=', _wfr.Rx, ' _wfr.Ry=', _wfr.Ry) + + if(_pres_ang != 0): srwl.SetRepresElecField(_wfr, 'a') + + arI = None + if(_int_type >= 0): + sNumTypeInt = 'f' + if(_int_type == 4): sNumTypeInt = 'd' + + #resMeshI = _wfr.mesh + resMeshI = deepcopy(_wfr.mesh) + arI = array(sNumTypeInt, [0]*resMeshI.ne*resMeshI.nx*resMeshI.ny) + srwl.CalcIntFromElecField(arI, _wfr, _pol, _int_type, _dep_type, resMeshI.eStart, resMeshI.xStart, resMeshI.yStart) + + if(_det is not None): #OC06122016 + #resStkDet = _det.treat_int(arI, resMeshI, _ord_interp=1) + resStkDet = _det.treat_int(arI, resMeshI) #OC11012017 + arI = resStkDet.arS + resMeshI = resStkDet.mesh + + if(len(_fname) > 0): + sValUnitName = 'ph/s/.1%bw/mm^2' #consider allowing for other units (for FEL applications) + + print('Saving Propagation Results ... ', end='') + t0 = time.time(); + srwl_uti_save_intens_ascii(arI, resMeshI, _fname, 0, ['Photon Energy', 'Horizontal Position', 'Vertical Position', ''], _arUnits=['eV', 'm', 'm', sValUnitName]) + print('completed (lasted', round(time.time() - t0, 2), 's)') + + #return arI + return arI, resMeshI #OC06122016 + + #------------------------------------------------------------------------ + #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None): + #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None): + #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None): #OC06122016 + def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _in_wre=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None, _me_approx=0): #OC05042017 + """Calculates multi-electron (/ partially coherent) SR emission and wavefront propagation + :param _mesh: mesh (grid) on which the initial wavefront has to be calculated (SRWLRadMesh instance) + :param _sr_samp_fact: oversampling factor for calculating of initial wavefront for subsequent propagation (effective if >0) + :param _sr_meth: SR Electric Field calculation method to be used (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") + :param _sr_rel_prec: relative precision for SR Electric Field calculation (usually 0.01 is OK, smaller the more accurate) + :param _in_wr: initial wavefront radius [m] to assume at wavefront propagation (is taken into account if != 0) + :param _in_wre: initial wavefront radius error [m] to assume at wavefront propagation (is taken into account if != 0) + :param _mag_type: "type" of magnetic field to use: + 1- "Approximate", referenced by self.mag_approx; + 2- "Accurate" (tabulated), referenced by self.mag; + :param _n_part_tot: total number of "macro-electrons" to be used in the calculation + :param _n_part_avg_proc: number of "macro-electrons" to be used in calculation at each "slave" before sending Stokes data to "master" (effective if the calculation is run via MPI) + :param _n_save_per: periodicity of saving intermediate average Stokes data to file by master process + :param _pres_ang: switch specifying presentation of the resulting Stokes parameters: coordinate (0) or angular (1) + :param _char: radiation characteristic to calculate: + 0- Intensity (s0); + 1- Four Stokes components; + 2- Mutual Intensity Cut vs X; + 3- Mutual Intensity Cut vs Y; + 4- Mutual Intensity Cut vs X & Y + :param _x0: horizontal center position for mutual intensity cut calculation + :param _y0: vertical center position for mutual intensity cut calculation + :param _e_ph_integ: integration over photon energy is required (1) or not (0); if the integration is required, the limits are taken from _mesh + :param _rand_meth: method for generation of pseudo-random numbers for e-beam phase-space integration: + 1- standard pseudo-random number generator + 2- Halton sequences + 3- LPtau sequences (to be implemented) + :param _fname: name of file to save the resulting data to + :param _det: detector structure ensuring a given final mesh on which the calculated intensity (or other characteristic) will be interpolated + :param _me_approx: multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance + :return: 1D array with (C-aligned) resulting intensity data + """ + + #if((_mesh == None) or (isinstance(_mesh, SRWLRadMesh) == False)): + if((_mesh is None) or (not isinstance(_mesh, SRWLRadMesh))): + raise Exception('Incorrect SRWLRadMesh structure') + + #if((hasattr(self, 'eBeam') == False) or (isinstance(self.eBeam, SRWLPartBeam) == False)): + if((not hasattr(self, 'eBeam')) or (not isinstance(self.eBeam, SRWLPartBeam))): + raise Exception('Incorrect electron beam (SRWLPartBeam) structure') + + #if((hasattr(self, 'optics') == False) or (isinstance(self.optics, SRWLOptC) == False)): + if((not hasattr(self, 'optics')) or (not isinstance(self.optics, SRWLOptC))): + raise Exception('Incorrect optics container (SRWLOptC) structure') + + if(_mag_type == 1): + if(self.mag_approx is None): Exception('Approximate Magnetic Field is not defined') + elif(_mag_type == 2): + if(self.mag is None): Exception('Magnetic Field is not defined') + else: Exception('Incorrect Magnetic Field type identificator') + + magToUse = self.mag_approx + if(_mag_type == 2): magToUse = self.mag + + #if((magToUse is None) and (self.gsnBeam is not None)): magToUse = self.gsnBeam #OC15092017 (because _mag is used for SRWLGsnBm when doing partially-coherent simulations in the scope of Gaussian-Schell model) + if(magToUse is None): + if(self.gsnBeam is not None): magToUse = self.gsnBeam #OC15092017 (because _mag is used for SRWLGsnBm when doing partially-coherent simulations in the scope of Gaussian-Schell model) + elif(self.ptSrc is not None): magToUse = self.ptSrc #OC16102017 (because _mag is used for SRWLPtSrc when doing partially-coherent simulations in the scope of Van-Cittert / Zernike model) + + return srwl_wfr_emit_prop_multi_e( + _e_beam = self.eBeam, _mag = magToUse, _mesh = _mesh, _sr_samp_fact = _sr_samp_fact, + #_sr_meth = _sr_meth, _sr_rel_prec = _sr_rel_prec, + #_sr_meth = _sr_meth, _sr_rel_prec = _sr_rel_prec, _w_wr = _in_wr, #OC26032016 + #_sr_meth = _sr_meth, _sr_rel_prec = _sr_rel_prec, _wr = _in_wr, #OC07092016 + _sr_meth = _sr_meth, _sr_rel_prec = _sr_rel_prec, _wr = _in_wr, _wre = _in_wre, #OC05012017 + _n_part_tot = _n_part_tot, _n_part_avg_proc = _n_part_avg_proc, _n_save_per = _n_save_per, + _file_path = _fname, + _opt_bl = self.optics, + _pres_ang = _pres_ang, _char = _char, _x0 = _x0, _y0 = _y0, + #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth) + #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det) #OC06122016 + #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det, _me_approx = _multi_e_approx) #OC05042017 + _e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det, _me_approx = _me_approx) #OC14042018 + + #------------------------------------------------------------------------ + ##def srwl_uti_parse_optics_par(self, _v): + #def parse_optics_par(self, _v): + # """Attempts to setup optical element container from list of optical element options + # :param _v: an object containing set of variables / options defining optical elements + # """ + #return None + + #------------------------------------------------------------------------ + def calc_all(self, _v, _op): + """Performs setup of electron beam, magnetic field, and performs calculations according to options specified in _v + :param _v: an object containing set of variables / options defining SR source and required calculations + :param _op: optical element container (SRWLOptC instance) that is assumed to be set up before calling this function and eventually used for wavefront propagation + """ + + #---main folder + if hasattr(_v, 'fdir'): self.dir_main = _v.fdir + + #---setup electron beam + #if(hasattr(_v, 'ebm_nm')): #To improve + # self.set_e_beam( + # _e_beam_name = (_v.ebm_nm + _v.ebm_nms), + # _i = _v.ebm_i, + # _sig_e = _v.ebm_ens, + # _emit_x = _v.ebm_emx, + # _emit_y = _v.ebm_emy, + # _drift = _v.ebm_dr, + # _x = _v.ebm_x, + # _y = _v.ebm_y, + # _xp = _v.ebm_xp, + # _yp = _v.ebm_yp, + # _dE = _v.ebm_de) + # #Re-define some 2-nd order moments, if necessary: + # if(_v.ebm_sigx > 0): self.eBeam.arStatMom2[0] = (_v.ebm_sigx)*(_v.ebm_sigx) + # if(_v.ebm_mxxp != 1.e+23): self.eBeam.arStatMom2[1] = _v.ebm_mxxp + # if(_v.ebm_sigxp > 0): self.eBeam.arStatMom2[2] = (_v.ebm_sigxp)*(_v.ebm_sigxp) + # if(_v.ebm_sigy > 0): self.eBeam.arStatMom2[3] = (_v.ebm_sigy)*(_v.ebm_sigy) + # if(_v.ebm_myyp != 1.e+23): self.eBeam.arStatMom2[4] = _v.ebm_myyp + # if(_v.ebm_sigyp > 0): self.eBeam.arStatMom2[5] = (_v.ebm_sigyp)*(_v.ebm_sigyp) + + if hasattr(_v, 'ebm_nm'): #MR28092016 + #OC: to check if the above is the right condition + self.set_e_beam( + _e_beam_name=(_v.ebm_nm + _v.ebm_nms), + _e_beam=None, + _i=_v.ebm_i, + _ens=_v.ebm_ens, + _emx=_v.ebm_emx, + _emy=_v.ebm_emy, + _dr=_v.ebm_dr, + _x=_v.ebm_x, + _y=_v.ebm_y, + _xp=_v.ebm_xp, + _yp=_v.ebm_yp, + _e=_v.ebm_e, + _de=_v.ebm_de, + # Twiss parameters: + _betax=_v.ebm_betax, + _alphax=_v.ebm_alphax, + _etax=_v.ebm_etax, + _etaxp=_v.ebm_etaxp, + _betay=_v.ebm_betay, + _alphay=_v.ebm_alphay, + _etay=_v.ebm_etay, + _etayp=_v.ebm_etayp, + # Moments: + _sigx=_v.ebm_sigx, + _sigxp=_v.ebm_sigxp, + _mxxp=_v.ebm_mxxp, + _sigy=_v.ebm_sigy, + _sigyp=_v.ebm_sigyp, + _myyp=_v.ebm_myyp) + + #print('e-beam was set up') + + #---setup magnetic field: undulator, sinusoidal approximation + #if hasattr(_v, 'und_b'): + if(hasattr(_v, 'und_b') or hasattr(_v, 'und_by') or hasattr(_v, 'und_bx')): #OC25052016 + if hasattr(_v, 'und_bx') == False: _v.und_bx = 0 + if hasattr(_v, 'und_by') == False: _v.und_by = _v.und_b + if hasattr(_v, 'und_phx') == False: _v.und_phx = 0 + if hasattr(_v, 'und_phy') == False: _v.und_phy = 0 + if hasattr(_v, 'und_zc') == False: _v.und_zc = 0 + if((_v.und_bx != 0) or (_v.und_by != 0)): #OC01062016 + self.set_und_sin(#setup approximate undulator field parameters + _per = _v.und_per, + _len = _v.und_len, + _bx = _v.und_bx, + _by = _v.und_by, + _phx = _v.und_phx, + _phy = _v.und_phy, + _sx = _v.und_sx, + _sy = _v.und_sy, + _zc = _v.und_zc) + self.mag = None + + if _v.und_b2e: + e1 = self.mag_approx.arMagFld[len(self.mag_approx.arMagFld) - 1].get_E1(_en_elec=self.eBeam.partStatMom1.get_E(), _unit='eV') + print('Fundamental Photon Energy:', srwl_uti_num_round(e1), 'eV') #check how it will work under IPython + + if _v.und_e2b: + b = self.mag_approx.arMagFld[len(self.mag_approx.arMagFld) - 1].E1_2_B(_e1=_v.w_e, _en_elec=self.eBeam.partStatMom1.get_E()) + print('Magnetic Field Amplitude:', srwl_uti_num_round(b), 'T') #check how it will work under IPython + + if(hasattr(_v, 'und2_b') or hasattr(_v, 'und2_by') or hasattr(_v, 'und2_bx')): #OC03122016 + if not hasattr(_v, 'und2_bx'): _v.und2_bx = 0 + if not hasattr(_v, 'und2_by'): _v.und2_by = _v.und2_b + if not hasattr(_v, 'und2_phx'): _v.und2_phx = 0 + if not hasattr(_v, 'und2_phy'): _v.und2_phy = 0 + if not hasattr(_v, 'und2_zc'): _v.und2_zc = 0 + if((_v.und2_bx != 0) or (_v.und2_by != 0)): + self.set_und_sin(#setup second approximate undulator field parameters + _per = _v.und2_per, + _len = _v.und2_len, + _bx = _v.und2_bx, + _by = _v.und2_by, + _phx = _v.und2_phx, + _phy = _v.und2_phy, + _sx = _v.und2_sx, + _sy = _v.und2_sy, + _zc = _v.und2_zc, + _add = 1) + + if((_v.und2_cma != 0) and (_v.und2_cml > 0)): #setting-up canting magnet (to move to a separate function and make more general; treat soft edges ensuring corrct kick angle) + self.set_mag_kick( + _angx = _v.und2_cma, + _angy = 0, + _len = _v.und2_cml, + _led = _v.und2_cmd, + _zc = _v.und2_cmz, + _add = 1) + + #---setup magnetic field: undulator, tabulated (e.g. measured) magnetic field + magnMeasDirExists = False + if hasattr(_v, 'und_mdir'): + self.dir_magn_meas = _v.und_mdir + if(len(self.dir_magn_meas) > 0): magnMeasDirExists = True + magnMeasSumFileExists = False + if hasattr(_v, 'und_mfs'): + self.fn_magn_meas_sum = _v.und_mfs + if(magnMeasDirExists): + testPath = os.path.join(os.getcwd(), self.dir_main, self.dir_magn_meas, self.fn_magn_meas_sum) + magnMeasSumFileExists = os.path.exists(testPath) + #print(testPath) + + if magnMeasSumFileExists and hasattr(_v, 'und_g'): + if(_v.und_g > 0.): + phase = 0. + if hasattr(_v, 'und_ph'): phase = _v.und_ph + phase_mode = 'p1' + if hasattr(_v, 'und_phm'): phase_mode = _v.und_phm + + self.set_und_tab(#setup undulator source from measured magnetic field data + _gap = _v.und_g, + _ph_mode = phase_mode, + _phase = phase, + _zc = _v.und_zc, + _interp_ord = 3, #1, + _meas_or_calc = 'm', + _per = _v.und_per, + _c1 = _v.und_c1, + _c2 = _v.und_c2, + _a = _v.und_a, + _dg_by_len = _v.und_dg/_v.und_len, + _y0 = _v.ebm_y + _v.ebm_yp*_v.und_zc - _v.und_dy, #this assumes that e-beam parameters are defined at z=0 + _yp = _v.ebm_yp - _v.und_yp) + + #if((_v.ss_mag == 1) or (_v.ss_mag == 1) or (_v.w_mag == 1) or (_v.tr_mag == 1)): + if((_v.ss and (_v.ss_mag == 1)) or (_v.sm and (_v.sm_mag == 1)) or ((_v.ws or _v.wm) and (_v.w_mag == 1)) or (_v.tr and (_v.tr_mag == 1))): + #print('test field conversion') + maxPer = _v.und_per + 0.01 + self.set_und_per_from_tab( + _rel_ac_thr=0.05, + _max_nh=7, + _max_per=maxPer) + + #self.mag_approx = None + ##forcing using tabulated field for whatever calculaitons (?): + #_v.ss_mag = 2 + #_v.w_mag = 2 + #_v.tr_mag = 2 + + #---setup magnetic field of a dipole magnet + if hasattr(_v, 'mag_bx') == False: _v.mag_bx = 0 + if hasattr(_v, 'mag_by') == False: _v.mag_by = 0 + if hasattr(_v, 'mag_gn') == False: _v.mag_gn = 0 + if hasattr(_v, 'mag_gs') == False: _v.mag_gs = 0 + if hasattr(_v, 'mag_len') == False: _v.mag_len = 1.5 #? + if hasattr(_v, 'mag_led') == False: _v.mag_led = 0 + if hasattr(_v, 'mag_r') == False: _v.mag_r = 0 + if hasattr(_v, 'mag_zc') == False: _v.mag_zc = 0 + if((_v.mag_bx != 0) or (_v.mag_by != 0) or (_v.mag_gn != 0) or (_v.mag_gs != 0)): + self.set_mag_multipole(#setup dipole / quad magnet parameters + _bx = _v.mag_bx, + _by = _v.mag_by, + _gn = _v.mag_gn, + _gs = _v.mag_gs, + _len = _v.mag_len, + _led = _v.mag_led, + _r = _v.mag_r, + _zc = _v.mag_zc) + #self.mag = None #OC16122016 (commented-out) + + #---setup magnetic field: tabulated + magnMeasDirExists = False + if hasattr(_v, 'mag_mdir'): + #self.dir_magn_meas = _v.mag_mdir + if(len(_v.mag_mdir) > 0): + if hasattr(_v, 'mag_ifn'): + magPath = os.path.join(os.getcwd(), self.dir_main, _v.mag_mdir, _v.mag_ifn) + + if(os.path.exists(magPath)): + #print("") + #print(magPath) + #print("") + self.set_mag_tab(#setup magnet from tabulated magnetic field data file + _fpath = magPath, + _zc = _v.mag_zc, + _interp_ord = 3) + + #self.mag_approx = None #OC16122016 (commented-out) + #forcing using tabulated field for whatever calculaitons (?): + #_v.ss_mag = 2 + #_v.w_mag = 2 + #_v.tr_mag = 2 + + #---setup Gaussian beam + if hasattr(_v, 'gbm_pen'): + if(_v.gbm_pen > 0): #OC11102017 + self.set_gsn_beam(#setup Gaussiam beam (i.e. only define parameters, without calculating wavefront) + _x = _v.gbm_x, + _y = _v.gbm_y, + _z = _v.gbm_z, + _xp = _v.gbm_xp, + _yp = _v.gbm_yp, + _avgPhotEn = _v.gbm_ave, + _pulseEn = _v.gbm_pen, + _repRate = _v.gbm_rep, + _polar = _v.gbm_pol, + _sigX = _v.gbm_sx, + _sigY = _v.gbm_sy, + _sigT = _v.gbm_st, + _mx = _v.gbm_mx, + _my = _v.gbm_my, + _presCA = _v.gbm_ca, + _presFT = _v.gbm_ft) + + #---setup Point Source (i.e. only define parameters, without calculating spherical wavefront) + if hasattr(_v, 'psc_fl'): + if(_v.psc_fl > 0): + self.set_pt_src(#setup Point Source (i.e. only define parameters, without calculating wavefront) + _x = _v.psc_x, + _y = _v.psc_y, + _z = _v.psc_z, + _flux = _v.psc_fl, + _unitFlux = _v.psc_ufl, + _polar = _v.psc_pol) + + #---calculate electron trajectory + if(_v.tr): + #print(self.eBeam.partStatMom1.z) + #trj = self.calc_el_trj( + _v.tr_res = self.calc_el_trj( #OC15112017 + _ctst = _v.tr_cti, _ctfi = _v.tr_ctf, _np = _v.tr_np, + _mag_type = _v.tr_mag, + _fname = os.path.join(_v.fdir, _v.tr_fn) if(len(_v.tr_fn) > 0) else '') + + #---setup detector (that may be used at different calculations) + detector = None + if((_v.d_rx > 0.) and (_v.d_nx > 0) and (_v.d_ry > 0.) and (_v.d_ny > 0)): #OC06122016 + detector = self.set_detector( + _x = _v.d_x, + _rx = _v.d_rx, + _nx = _v.d_nx, + _dx = _v.d_dx, + _y = _v.d_y, + _ry = _v.d_ry, + _ny = _v.d_ny, + _dy = _v.d_dy, + _ord = _v.d_or, + _fname = os.path.join(_v.fdir, _v.d_ifn) if(len(_v.d_ifn) > 0) else '') + + #---calculate single-e spectrum vs photon energy + if(_v.ss or _v.gs): + mesh_ss = SRWLRadMesh( + _v.ss_ei, _v.ss_ef, _v.ss_ne, + _v.ss_x, _v.ss_x, 1, + _v.ss_y, _v.ss_y, 1, + _v.op_r) + + srCanBeCalc = (self.eBeam is not None) and ((self.mag_approx is not None) or (self.mag is not None)) + #print(" _v.ss=", _v.ss) + #print(" _v.gs=", _v.gs) + + if((_v.gs != True) and (srCanBeCalc == True)): + #print(" Before calc_sr_se") + #print(" self.mag=", self.mag) + #wfr_ss, int_ss = self.calc_sr_se( + #wfr_ss, int_ss, mesh_dummy = self.calc_sr_se( #OC06122016 + _v.w_res, _v.ss_res, mesh_dummy = self.calc_sr_se( #OC16102017 + _mesh = mesh_ss, + _meth = _v.ss_meth, + _rel_prec = _v.ss_prec, + _zi = _v.ss_zi, + _zf = _v.ss_zf, + _pol = _v.ss_pol, + _int_type = 0, + _mag_type = _v.ss_mag, + _fname = os.path.join(_v.fdir, _v.ss_fn) if(len(_v.ss_fn) > 0) else '') + + if((_v.gs == True) or ((self.gsnBeam is not None) and (srCanBeCalc == False))): + #wfr_ss, int_ss = self.calc_rad_gsn( + #wfr_ss, int_ss, mesh_dummy = self.calc_rad_gsn( #OC06122016 + _v.w_res, _v.ss_res, mesh_dummy = self.calc_rad_gsn( #OC16102017 + _mesh = mesh_ss, + _pol = _v.ss_pol, + _int_type = 0, + _presFT = _v.ss_ft, + _unitE = _v.ss_u, + _fname = os.path.join(_v.fdir, _v.ss_fn) if(len(_v.ss_fn) > 0) else '') + + #---calculate multi-e spectrum vs photon energy + if(_v.sm): + mesh_sm = SRWLRadMesh( + _v.sm_ei, _v.sm_ef, _v.sm_ne, + _v.sm_x - 0.5*_v.sm_rx, _v.sm_x + 0.5*_v.sm_rx, _v.sm_nx, + _v.sm_y - 0.5*_v.sm_ry, _v.sm_y + 0.5*_v.sm_ry, _v.sm_ny, + _v.op_r) + if((_v.sm_mag == 1) and (_v.sm_meth < 0)): + #int_sm = self.calc_ur_spec_me( + _v.sm_res = self.calc_ur_spec_me( #OC16102017 + _mesh = mesh_sm, + _harm_init = _v.sm_hi, + _harm_fin = _v.sm_hf, + _prec_long = _v.sm_prl, + _prec_azim = _v.sm_pra, + _type = _v.sm_type, + _pol = _v.sm_pol, + _fname = os.path.join(_v.fdir, _v.sm_fn) if(len(_v.sm_fn) > 0) else '') + else: #for "accurate" magnetic field + #int_sm = self.calc_arb_spec_me( + _v.sm_res = self.calc_arb_spec_me( #OC16102017 + _mesh = mesh_sm, + _meth = _v.sm_meth, + _rel_prec = _v.sm_prec, + _n_part_tot = _v.sm_nm, + _n_part_avg_proc = _v.sm_na, + _n_save_per = _v.sm_ns, + _type = _v.sm_type, + _mag = _v.sm_mag, + _pol = _v.sm_pol, + _rand_meth = _v.sm_rm, + _fname = os.path.join(_v.fdir, _v.sm_fn) if(len(_v.sm_fn) > 0) else '', + _sr_samp_fact = _v.sm_smpf, + _det = detector, + _me_approx = _v.sm_am) #OC13042018 + + #---calculate undulator "operation table", i.e. dependence of gap (and phase) on photon energy (for a given polarization) + if(_v.ut): + #phase_mode = 'p1' + #if hasattr(_v, 'und_phm'): phase_mode = _v.und_phm + mesh_sm = SRWLRadMesh( + _v.sm_ei, _v.sm_ef, _v.sm_ne, + _v.sm_x - 0.5*_v.sm_rx, _v.sm_x + 0.5*_v.sm_rx, _v.sm_nx, + _v.sm_y - 0.5*_v.sm_ry, _v.sm_y + 0.5*_v.sm_ry, _v.sm_ny, + _v.op_r) + #print('_v.sm_rx=', _v.sm_rx, '_v.sm_ry=', _v.sm_ry) + + self.calc_und_oper_tab( + _mesh = mesh_sm, + _pol = _v.sm_pol, + _hi = _v.sm_hi, + _hf = _v.sm_hf, + _meas_or_calc = 'm', + _zc = _v.und_zc, + _fname = os.path.join(_v.fdir, _v.ut_fn) if(len(_v.ut_fn) > 0) else '') + + #---calculate SR power density distribution + if(_v.pw): + mesh_pw = SRWLRadMesh( + 1000, 1000, 1, #dummy (not used for power density) + _v.pw_x - 0.5*_v.pw_rx, _v.pw_x + 0.5*_v.pw_rx, _v.pw_nx, + _v.pw_y - 0.5*_v.pw_ry, _v.pw_y + 0.5*_v.pw_ry, _v.pw_ny, + _v.op_r) + #int_pw = self.calc_pow_den( + _v.pw_res = self.calc_pow_den( #OC16102017 + _mesh = mesh_pw, + _prec = _v.pw_pr, + _meth = _v.pw_meth, + #_z_start = _v.pw_zst, + #_z_fin = _v.pw_zfi, + _z_start = _v.pw_zi, + _z_fin = _v.pw_zf, + _mag_type = _v.pw_mag, + _fname= os.path.join(_v.fdir, _v.pw_fn) if(len(_v.pw_fn) > 0) else '') + + #---calculate single-e and multi-e intensity distributions (before and after wavefront propagation through a beamline) + if(_v.si or _v.ws or _v.gi or _v.wg or _v.wm): + #if(_v.ws or _v.wg or _v.wm): self.set_optics(_op) + if(_v.ws or _v.wg or _v.wm): self.set_optics(_op, _v) #OC28042018 + + ef = _v.w_e + if(_v.w_ef > 0): ef = _v.w_ef + mesh_w = SRWLRadMesh( + _v.w_e, ef, _v.w_ne, + _v.w_x - 0.5*_v.w_rx, _v.w_x + 0.5*_v.w_rx, _v.w_nx, + _v.w_y - 0.5*_v.w_ry, _v.w_y + 0.5*_v.w_ry, _v.w_ny, + _v.op_r) + #---calculate single-e electric field and intensity (before wavefront propagation through a beamline) + if(_v.si or _v.ws or _v.gi or _v.wg): + + srCanBeCalc = (self.eBeam is not None) and ((self.mag_approx is not None) or (self.mag is not None)) + gsnBeamCanBeCalc = (self.gsnBeam is not None) + + ptSrcSphWaveCanBeCalc = False + if(hasattr(self, 'ptSrc')): ptSrcSphWaveCanBeCalc = (self.ptSrc is not None) + + #print(self.gsnBeam) + detForSI = None if((_v.wg is True) or (_v.ws is True)) else detector + #print('detForSI=', detForSI) + + #OC05042018 + wfrWasNotLoaded = True + if(len(_v.ws_fnei) > 0): + print('Loading initial wavefront data from file ... ', end='') + t0 = time.time(); + fnWfr = os.path.join(_v.fdir, _v.ws_fnei) + in_s = open(fnWfr, 'rb') + _v.w_res = pickle.load(in_s) + in_s.close() + if(_v.w_res is not None): + _v.si_res, mesh_si = self.calc_int_from_wfr(_v.w_res, _v.si_pol, _v.si_type, detForSI, _pr=False) + wfrWasNotLoaded = False + print('completed (lasted', round(time.time() - t0, 2), 's)') + else: print('failed to load wavefront file') + + if wfrWasNotLoaded: + #if((_v.gi == False) and (_v.wg == False) and (srCanBeCalc == True)): + if((_v.gi != True) and (_v.wg != True) and (srCanBeCalc == True)): + + #print('Before wfr, int_w0 = self.calc_sr_se') + + #wfr, int_w0 = self.calc_sr_se( + #wfr, int_w0, mesh_si = self.calc_sr_se( #OC06122016 + _v.w_res, _v.si_res, mesh_si = self.calc_sr_se( #OC16102017 + _mesh = deepcopy(mesh_w), + _samp_fact = _v.w_smpf, + _meth = _v.w_meth, + _rel_prec = _v.w_prec, + _zi = _v.w_zi, + _zf = _v.w_zf, + _pol = _v.si_pol, + _int_type = _v.si_type, + _mag_type = _v.w_mag, + _fname = os.path.join(_v.fdir, _v.si_fn) if(len(_v.si_fn) > 0) else '', + _det = detForSI) + + #if((_v.gs == True) or ((gsnBeamCanBeCalc == True) and (srCanBeCalc == False))): + if((_v.gs == True) or (_v.wg == True) or ((gsnBeamCanBeCalc == True) and (srCanBeCalc == False))): #OC01062016 + #wfr, int_w0 = self.calc_rad_gsn( + #wfr, int_w0, mesh_si = self.calc_rad_gsn( #OC06122016 + _v.w_res, _v.si_res, mesh_si = self.calc_rad_gsn( #OC16102017 + _mesh = deepcopy(mesh_w), + _samp_fact = _v.w_smpf, + _pol = _v.si_pol, + _int_type = _v.si_type, + _presFT = _v.w_ft, + _unitE = _v.w_u, + _fname = os.path.join(_v.fdir, _v.si_fn) if(len(_v.si_fn) > 0) else '', + _det = detForSI) + + if((ptSrcSphWaveCanBeCalc is True) and (gsnBeamCanBeCalc is not True) and (srCanBeCalc is not True)): #OC11102017 + #wfr, int_w0, mesh_si = self.calc_rad_pt_src( + _v.w_res, _v.si_res, mesh_si = self.calc_rad_pt_src( #OC16102017 + _mesh = deepcopy(mesh_w), + _samp_fact = _v.w_smpf, + _pol = _v.si_pol, + _int_type = _v.si_type, + _presFT = _v.w_ft, + _unitE = _v.w_u, + _fname = os.path.join(_v.fdir, _v.si_fn) if(len(_v.si_fn) > 0) else '', + _det = detForSI) + + if((len(_v.ws_fne) > 0) and (_v.w_res is not None)): #OC05042018 + #Dumping initial wavefront + print('Saving initial wavefront data to a file ... ', end='') + t0 = time.time(); + fnWfr = os.path.join(_v.fdir, _v.ws_fne) + out_s = open(fnWfr, 'wb') + pickle.dump(_v.w_res, out_s) + out_s.flush() + out_s.close() + print('completed (lasted', round(time.time() - t0, 2), 's)') + + #mesh_si = deepcopy(wfr.mesh) #OC06122016 (commented-out) + #if(detForSI is None): mesh_si = deepcopy(wfr.mesh) + + #print('mesh_si.eStart=', mesh_si.eStart, 'mesh_si.eFin=', mesh_si.eFin, 'mesh_si.ne=', mesh_si.ne) + #print('mesh_si.xStart=', mesh_si.xStart, 'mesh_si.xFin=', mesh_si.xFin, 'mesh_si.nx=', mesh_si.nx) + #print('mesh_si.yStart=', mesh_si.yStart, 'mesh_si.yFin=', mesh_si.yFin, 'mesh_si.ny=', mesh_si.ny) + + #---calculate single-e electric field and intensity (after wavefront propagation through a beamline) + if(_v.ws or _v.wg): + #if(_v.ws or _v.wg or _v.wsm): #OC10052016 (commented-out) + + if(_v.w_wr != 0.): #OC26032016 + #wfr.Rx = _v.w_wr + #wfr.Ry = _v.w_wr + _v.w_res.Rx = _v.w_wr #OC16102017 + _v.w_res.Ry = _v.w_wr + + if(_v.w_wre > 0.): #OC05012017 + #wfr.dRx = _v.w_wre + #wfr.dRy = _v.w_wre + _v.w_res.dRx = _v.w_wre #OC16102017 + _v.w_res.dRy = _v.w_wre + + #int_ws = self.calc_wfr_prop( + #int_ws, mesh_ws = self.calc_wfr_prop( #OC06122016 + _v.ws_res, mesh_ws = self.calc_wfr_prop( #OC16102017 + #_wfr = wfr, + _wfr = _v.w_res, #OC16102017 + _pres_ang = _v.ws_ap, + _pol = _v.si_pol, + _int_type = _v.si_type, + _dep_type=3, #consider adding other cases (e.g. for TD FEL calculations) + _fname = os.path.join(_v.fdir, _v.ws_fni) if(len(_v.ws_fni) > 0) else '', + _det = detector) + #mesh_ws = wfr.mesh #OC06122016 (commented-out) + #if(len(_v.ws_fn) > 0): to implement saving single-e (/ fully coherent) wavefront data (wfr) to a file + + if((len(_v.ws_fnep) > 0) and (_v.w_res is not None)): #OC05042018 + #Dumping propagated wavefront + print('Saving propagated wavefront data to a file ... ', end='') + t0 = time.time(); + fnWfr = os.path.join(_v.fdir, _v.ws_fnep) + out_s = open(fnWfr, 'wb') + pickle.dump(_v.w_res, out_s) + out_s.flush() + out_s.close() + print('completed (lasted', round(time.time() - t0, 2), 's)') + + #---calculate multi-electron (/ partially coherent) wavefront propagation + if(_v.wm): + #wmResFileName = os.path.join(_v.fdir, _v.wm_fni) if(len(_v.wm_fni) > 0) else None + #print(wmResFileName) + + res_ipm = self.calc_wfr_emit_prop_me( + _mesh = mesh_w, + _sr_samp_fact = _v.w_smpf, + _sr_meth = _v.w_meth, + _sr_rel_prec = _v.w_prec, + _in_wr = _v.w_wr, + _in_wre = _v.w_wre, #OC05012017 + _mag_type = _v.w_mag, + _n_part_tot = _v.wm_nm, + _n_part_avg_proc = _v.wm_na, + _n_save_per = _v.wm_ns, + _pres_ang = _v.wm_ap, + _char = _v.wm_ch, + _x0 = _v.wm_x0, + _y0 = _v.wm_y0, + _e_ph_integ = _v.wm_ei, + _rand_meth = _v.wm_rm, + _fname = os.path.join(_v.fdir, _v.wm_fni) if(len(_v.wm_fni) > 0) else None, + _det = detector, + #_multi_e_approx = _v.wm_am) + _me_approx = _v.wm_am) #OC13042018 + + #---plot results of all calculatiopns here (because the plotting "from the middle of the script" may hang up script execution) + #uti_plot_init('TkAgg') #make the backend name an input option or move this to uti_plot ? + plotOK = False + + #if (_v.tr == True) and (len(_v.tr_pl) > 0): + if (_v.tr) and (len(_v.tr_pl) > 0): #OC06042018 (to make sure that it starts when _v.tr = 1) + + #args = [] + #kwargs = { + # 'labels': ['Longitudinal Position'], + # 'units': ['m', 'm'], + #} + ##OC: add more options: 'xpz', 'ypz', 'xy',... + #traj_rep_allowed_values = ['xz', 'yz'] + #traj_rep_allowed_values += [x.upper() for x in traj_rep_allowed_values] + + #if _v.tr_pl.lower() == 'xz': + # args.append(trj.arX) + # kwargs['labels'].append('Horizontal Position') + #elif _v.tr_pl.lower() == 'yz': + # args.append(trj.arY) + # kwargs['labels'].append('Vertical Position') + #else: + # raise ValueError('No such option allowed: {}. Allowed values: {}'.format(_v.tr_pl, traj_rep_allowed_values)) + #kwargs['labels'].append('Electron Trajectory') + #args.append([min(trj.arZ), max(trj.arZ), len(trj.arZ)]) + #uti_plot1d(*args, **kwargs) + + #OC15112017 + strSep = ',' #The possible separators are actually ',' and ' ' + strAuxOpt = copy(_v.tr_pl) + strAuxOpt = strAuxOpt.replace(strSep, ' ') + arOpt = strAuxOpt.split(' ') + trj = _v.tr_res + + for i in range(len(arOpt)): + curOpt = copy(arOpt[i]) + curOpt = curOpt.replace(' ', '') + if(len(curOpt) > 0): + arPlotAbsc = None #reference to Abscissa array + arPlotOrd = None #reference to Ordinate array + gridIsReg = False + labels = None + units = None + curOpt = curOpt.lower() + if(curOpt == 'xz'): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arX; gridIsReg = True + labels = ['Longitudinal Position', 'Horizontal Position', 'Horizontal Trajectory'] + units = ['m', 'm'] + elif(curOpt == 'xpz'): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arXp; gridIsReg = True + labels = ['Longitudinal Position', 'Horizontal Angle', 'Horizontal Trajectory'] + units = ['m', 'rad'] + elif(curOpt == 'yz'): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arY; gridIsReg = True + labels = ['Longitudinal Position', 'Vertical Position', 'Vertical Trajectory'] + units = ['m', 'm'] + elif(curOpt == 'ypz'): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arYp; gridIsReg = True + labels = ['Longitudinal Position', 'Vertical Angle', 'Vertical Trajectory'] + units = ['m', 'rad'] + elif(curOpt == 'yx'): + arPlotAbsc = trj.arX; arPlotOrd = trj.arY + labels = ['Horizontal Position', 'Vertical Position', 'Transverse Trajectory'] + units = ['m', 'm'] + elif(curOpt == 'xy'): + arPlotAbsc = trj.arY; arPlotOrd = trj.arX + labels = ['Vertical Position', 'Horizontal Position', 'Transverse Trajectory'] + units = ['m', 'm'] + elif(curOpt == 'ypxp'): + arPlotAbsc = trj.arXp; arPlotOrd = trj.arYp + labels = ['Horizontal Angle', 'Vertical Angle', 'Transverse Trajectory'] + units = ['rad', 'rad'] + elif(curOpt == 'xpyp'): + arPlotAbsc = trj.arYp; arPlotOrd = trj.arXp + labels = ['Vertical Angle', 'Horizontal Angle', 'Transverse Trajectory'] + units = ['rad', 'rad'] + elif(curOpt == 'bxz'): + bxExists = False + if(hasattr(trj, 'arBx')): + if(trj.arBx is not None): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arBx; gridIsReg = True + labels = ['Longitudinal Position', 'Horizontal Magnetic Field', 'Magnetic Field'] + units = ['m', 'T'] + bxExists = True + if(not bxExists): raise ValueError('Horizontal magnetic field seen by electron was not calculated') + elif(curOpt == 'byz'): + byExists = False + if(hasattr(trj, 'arBy')): + if(trj.arBy is not None): + arPlotAbsc = trj.arZ; arPlotOrd = trj.arBy; gridIsReg = True + labels = ['Longitudinal Position', 'Vertical Magnetic Field', 'Magnetic Field'] + units = ['m', 'T'] + byExists = True + if(not byExists): raise ValueError('Vertical magnetic field seen by electron was not calculated') + + if((arPlotAbsc is not None) and (arPlotOrd is not None)): + if(gridIsReg): uti_plot1d(arPlotOrd, [min(arPlotAbsc), max(arPlotAbsc), len(arPlotAbsc)], labels, units) + else: uti_plot1d_ir(arPlotOrd, arPlotAbsc, labels, units) + else: raise ValueError('This trajectory plot option value is not supported: {}. The supported values are: xz,xpz,yz,ypz,yx,ypxp,bxz,byz'.format(curOpt)) + + plotOK = True + + if((_v.ss or _v.gs) and (len(_v.ss_pl) > 0)): + + sArgLabel = 'Photon Energy' + sArgUnit = 'eV' + if(_v.ss_ft == 't'): + sArgLabel = 'Time' + sArgUnit = 's' + + sValLabel = 'Flux per Unit Surface' + sValUnit = 'ph/s/.1%bw/mm^2' + if(_v.w_u == 0): + sValLabel = 'Intensity' + sValUnit = 'a.u.' + elif(_v.w_u == 2): + if(_v.ss_ft == 't'): + sValLabel = 'Power Density' + sValUnit = 'W/mm^2' + elif(_v.ss_ft == 'f'): + sValLabel = 'Spectral Fluence' + sValUnit = 'J/eV/mm^2' + + #uti_plot1d(int_ss, [mesh_ss.eStart, mesh_ss.eFin, mesh_ss.ne], [sArgLabel, sValLabel, sValLabel], [sArgUnit, sValUnit]) + uti_plot1d(_v.ss_res, [mesh_ss.eStart, mesh_ss.eFin, mesh_ss.ne], [sArgLabel, sValLabel, sValLabel], [sArgUnit, sValUnit]) #OC16102017 + + plotOK = True + + if (_v.sm == True) and (len(_v.sm_pl) > 0): + sValType = 'Flux'; sValUnit = 'ph/s/.1%bw' + if(_v.sm_type == 2): + sValType = 'Flux per Unit Surface'; sValUnit = 'ph/s/.1%bw/mm^2' + #uti_plot1d(int_sm, [mesh_sm.eStart, mesh_sm.eFin, mesh_sm.ne], ['Photon Energy', sValType, sValType], ['eV', sValUnit]) + uti_plot1d(_v.sm_res, [mesh_sm.eStart, mesh_sm.eFin, mesh_sm.ne], ['Photon Energy', sValType, sValType], ['eV', sValUnit]) + + plotOK = True + + if (_v.pw == True) and (len(_v.pw_pl) > 0): + if ((_v.pw_pl == 'xy') or (_v.pw_pl == 'yx') or (_v.pw_pl == 'XY') or (_v.pw_pl == 'YX')) and (_v.pw_nx > 1) and (_v.pw_ny > 1): + uti_plot2d1d( + _v.pw_res, #int_pw, #OC16102017 + [mesh_pw.xStart, mesh_pw.xFin, mesh_pw.nx], + [mesh_pw.yStart, mesh_pw.yFin, mesh_pw.ny], + 0.5*(mesh_pw.xStart + mesh_pw.xFin), + 0.5*(mesh_pw.yStart + mesh_pw.yFin), + ['Horizontal Position', 'Vertical Position', 'Power Density'], + ['m', 'm', 'W/mm^2'], True) + elif ((_v.pw_pl == 'x') or (_v.pw_pl == 'X')) and (_v.pw_nx > 1): + #uti_plot1d(int_pw, [mesh_pw.xStart, mesh_pw.xFin, mesh_pw.nx], + uti_plot1d(_v.pw_res, [mesh_pw.xStart, mesh_pw.xFin, mesh_pw.nx], #OC16102017 + ['Horizontal Position', 'Power Density', 'Power Density'], + ['m', 'W/mm^2']) + elif ((_v.pw_pl == 'y') or (_v.pw_pl == 'Y')) and (_v.pw_ny > 1): + #uti_plot1d(int_pw, [mesh_pw.yStart, mesh_pw.yFin, mesh_pw.ny], + uti_plot1d(_v.pw_res, [mesh_pw.yStart, mesh_pw.yFin, mesh_pw.ny], #OC16102017 + ['Vertical Position', 'Power Density', 'Power Density'], + ['m', 'W/mm^2']) + plotOK = True + + if (_v.si or _v.gs) and (len(_v.si_pl) > 0): + if _v.si_pl in ['xy', 'yx', 'XY', 'YX']: + + sValLabel = 'Flux per Unit Surface' + sValUnit = 'ph/s/.1%bw/mm^2' + if(_v.w_u == 0): + sValLabel = 'Intensity' + sValUnit = 'a.u.' + elif(_v.w_u == 2): + if(_v.w_ft == 't'): + sValLabel = 'Power Density' + sValUnit = 'W/mm^2' + elif(_v.w_ft == 'f'): + sValLabel = 'Spectral Fluence' + sValUnit = 'J/eV/mm^2' + + #print('testing', _v.si_pl) + uti_plot2d1d( + #int_w0, + _v.si_res, #OC16102017 + [mesh_si.xStart, mesh_si.xFin, mesh_si.nx], + [mesh_si.yStart, mesh_si.yFin, mesh_si.ny], + 0, #0.5*(mesh_si.xStart + mesh_si.xFin), + 0, #0.5*(mesh_si.yStart + mesh_si.yFin), + ['Horizontal Position', 'Vertical Position', sValLabel], + ['m', 'm', sValUnit], #add other units for FEL + True) + plotOK = True + + #if _v.ws and (len(_v.ws_pl) > 0): + if (_v.ws or _v.wg) and (len(_v.ws_pl) > 0): #OC01062016 + if (_v.ws_pl == 'xy') or (_v.ws_pl == 'yx') or (_v.ws_pl == 'XY') or (_v.ws_pl == 'YX'): + #print('2D plot panel is to be prepared') + + sValLabel = 'Flux per Unit Surface' + sValUnit = 'ph/s/.1%bw/mm^2' + if(_v.w_u == 0): + sValLabel = 'Intensity' + sValUnit = 'a.u.' + elif(_v.w_u == 2): + if(_v.w_ft == 't'): + sValLabel = 'Power Density' + sValUnit = 'W/mm^2' + elif(_v.w_ft == 'f'): + sValLabel = 'Spectral Fluence' + sValUnit = 'J/eV/mm^2' + + uti_plot2d1d( + #int_w0, + _v.si_res, #OC16102017 + [mesh_si.xStart, mesh_si.xFin, mesh_si.nx], + [mesh_si.yStart, mesh_si.yFin, mesh_si.ny], + 0, #0.5*(mesh_si.xStart + mesh_si.xFin), + 0, #0.5*(mesh_si.yStart + mesh_si.yFin), + ['Horizontal Position', 'Vertical Position', sValLabel + ' Before Propagation'], + ['m', 'm', sValUnit], + True) + uti_plot2d1d( + #int_ws, + _v.ws_res, #OC16102017 + [mesh_ws.xStart, mesh_ws.xFin, mesh_ws.nx], + [mesh_ws.yStart, mesh_ws.yFin, mesh_ws.ny], + 0, #0.5*(mesh_ws.xStart + mesh_ws.xFin), + 0, #0.5*(mesh_ws.yStart + mesh_ws.yFin), + ['Horizontal Position', 'Vertical Position', sValLabel + ' After Propagation'], + ['m', 'm', sValUnit], + True) + + #to continue here + + plotOK = True + + if(plotOK): uti_plot_show() + +#**************************************************************************** +def srwl_uti_parse_str2list(_str): + """Parse _str, such as '1 2 3' or '1,2,3', to list + """ + sLoc = copy(_str) + sLoc = sLoc.replace('[', ''); sLoc = sLoc.replace(']', '') + sLoc = sLoc.replace('(', ''); sLoc = sLoc.replace(')', '') + sLoc = sLoc.replace('{', ''); sLoc = sLoc.replace('}', '') + + resList = [] + if(',' in sLoc): resList = sLoc.split(',') + elif(';' in sLoc): resList = sLoc.split(';') + else: resList = sLoc.split(' ') + + for i in range(len(resList)): + resList[i] = float(resList[i]) + + return resList + +#**************************************************************************** +def srwl_uti_std_options(): + """Defines sets of standard default options (applicable to any beamline) for general types of calculation + :returns: list providing compact description of all options; every element of this list is supposed to contain: + [0]: string containing option (/ variable) name + [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) + [2]: default value + [3]: string containing help / explanation of the option / variable + [4]: optional string describing formal action to be taken if option is fired + """ + varParamStd = [ +#---Electron Beam + ['ebm_nm', 's', 'NSLS-II Low Beta ', 'standard electron beam name'], + ['ebm_nms', 's', 'Day1', 'standard electron beam name suffix: e.g. can be Day1, Final'], + ['ebm_i', 'f', 0.5, 'electron beam current [A]'], + ['ebm_e', 'f', 3., 'electron beam avarage energy [GeV]'], + ['ebm_de', 'f', 0., 'electron beam average energy deviation [GeV]'], + ['ebm_x', 'f', 0., 'electron beam initial average horizontal position [m]'], + ['ebm_y', 'f', 0., 'electron beam initial average vertical position [m]'], + ['ebm_xp', 'f', 0., 'electron beam initial average horizontal angle [rad]'], + ['ebm_yp', 'f', 0., 'electron beam initial average vertical angle [rad]'], + #['ebm_z', 'f', 0., 'electron beam initial average longitudinal position [m]'], #it is always assumed to be 0. + ['ebm_dr', 'f', 0., 'electron beam longitudinal drift [m] to be performed before a required calculation'], + ['ebm_ens', 'f', -1, 'electron beam relative energy spread'], + ['ebm_emx', 'f', -1, 'electron beam horizontal emittance [m]'], + ['ebm_emy', 'f', -1, 'electron beam vertical emittance [m]'], + # Definition of the beam through Twiss parameters: #MR28092016 + ['ebm_betax', 'f', None, 'horizontal beta-function [m]'], #OC: re-check the default values + ['ebm_alphax', 'f', None, 'horizontal alpha-function [rad]'], + ['ebm_etax', 'f', None, 'horizontal dispersion function [m]'], + ['ebm_etaxp', 'f', None, 'horizontal dispersion function derivative [rad]'], + ['ebm_betay', 'f', None, 'vertical beta-function [m]'], + ['ebm_alphay', 'f', None, 'vertical alpha-function [rad]'], + ['ebm_etay', 'f', None, 'vertical dispersion function [m]'], + ['ebm_etayp', 'f', None, 'vertical dispersion function derivative [rad]'], + # Definition of the beam through Moments: + ['ebm_sigx', 'f', None, 'horizontal RMS size of electron beam [m]'], + ['ebm_sigy', 'f', None, 'vertical RMS size of electron beam [m]'], + ['ebm_sigxp', 'f', None, 'horizontal RMS angular divergence of electron beam [rad]'], + ['ebm_sigyp', 'f', None, 'vertical RMS angular divergence of electron beam [rad]'], + ['ebm_mxxp', 'f', None, 'horizontal position-angle mixed 2nd order moment of electron beam [m]'], + ['ebm_myyp', 'f', None, 'vertical position-angle mixed 2nd order moment of electron beam [m]'], + #['ebm_sigx', 'f', -1, 'horizontal RMS size of electron beam [m] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + #['ebm_sigy', 'f', -1, 'vertical RMS size of electron beam [m] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + #['ebm_sigxp', 'f', -1, 'horizontal RMS angular divergence of electron beam [rad] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + #['ebm_sigyp', 'f', -1, 'vertical RMS angular divergence of electron beam [rad] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + #['ebm_mxxp', 'f', 1.e+23, 'horizontal position-angle mixed 2nd order moment of electron beam [m] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + #['ebm_myyp', 'f', 1.e+23, 'vertical position-angle mixed 2nd order moment of electron beam [m] (is taken into account if > 0, in that case it overrides Emittance and Twiss parameters)'], + +#---Undulator + ['und_per', 'f', 0.02, 'undulator period [m]'], + ['und2_per', 'f', 0.02, 'undulator period [m]'], + ['und_len', 'f', 3., 'undulator length [m]'], + ['und2_len', 'f', 3., 'undulator length [m]'], + ['und_b', 'f', 0., 'undulator vertical peak magnetic field [T]'], #Keeping it 0 here is important for parsing calculation options! + ['und2_b', 'f', 0., 'undulator vertical peak magnetic field [T]'], #Keeping it 0 here is important for parsing calculation options! + ['und_bx', 'f', 0., 'undulator horizontal peak magnetic field [T]'], + ['und2_bx', 'f', 0., 'undulator horizontal peak magnetic field [T]'], + #['und_by', 'f', 0., 'undulator vertical peak magnetic field [T]'], + #['und2_by', 'f', 0., 'undulator vertical peak magnetic field [T]'], + ['und_g', 'f', 0., 'undulator gap [mm] (assumes availability of magnetic measurement or simulation data)'], + ['und2_g', 'f', 0., 'second undulator gap [mm] (assumes availability of magnetic measurement or simulation data)'], + + ['und_ph', 'f', 0., 'undulator phase, i.e. longitudinal shift of magnet arrays [mm] (assumes availability of magnetic measurement or simulation data)'], + ['und2_ph', 'f', 0., 'second undulator phase, i.e. longitudinal shift of magnet arrays [mm] (assumes availability of magnetic measurement or simulation data)'], + ['und_phm', 's', 'p1', 'undulator phase move mode'], + ['und2_phm', 's', 'p1', 'second undulator phase move mode'], + + ['und_sx', 'i', 1, 'undulator horizontal magnetic field symmetry vs longitudinal position'], + ['und2_sx', 'i', 1, 'undulator horizontal magnetic field symmetry vs longitudinal position'], + ['und_sy', 'i', -1, 'undulator vertical magnetic field symmetry vs longitudinal position'], + ['und2_sy', 'i', -1, 'undulator vertical magnetic field symmetry vs longitudinal position'], + ['und_zc', 'f', 0., 'undulator center longitudinal position [m]'], + ['und2_zc', 'f', 0., 'second undulator center longitudinal position [m]'], + + ['und2_cma', 'f', 0., 'canting magnet angle [rad]'], + ['und2_cmz', 'f', 0., 'canting magnet longitudinal position [m]'], + ['und2_cml', 'f', 0., 'canting magnet effective length [m]'], + ['und2_cmd', 'f', 0., 'canting magnet edge length [m]'], + + ['und_b0', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. b0 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und2_b0', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. b0 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und_c1', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. c1 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und2_c1', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. c1 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und_c2', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. c2 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und2_c2', 'f', 0., 'constant defining (approximate) undulator field dependence on gap (i.e. c2 in b0*exp(-c1*gap/per + c2*(gap/per)^2))'], + ['und_a', 'f', 0., 'constant defining (approximate) undulator field dependence on vertical position (i.e. a in cosh(2*Pi*a*y/per)'], + ['und2_a', 'f', 0., 'constant defining (approximate) undulator field dependence on vertical position (i.e. a in cosh(2*Pi*a*y/per)'], + + ['und_dg', 'f', 0., 'undulator gap taper, i.e. gap difference between exit and entrance [m]'], + ['und2_dg', 'f', 0., 'undulator gap taper, i.e. gap difference between exit and entrance [m]'], + ['und_dy', 'f', 0., 'undulator elevation in vertical direction over the median plane [m]'], + ['und2_dy', 'f', 0., 'undulator elevation in vertical direction over the median plane [m]'], + ['und_yp', 'f', 0., 'undulator vertical angular misalignment over the median plane [rad]'], + ['und2_yp', 'f', 0., 'undulator vertical angular misalignment over the median plane [rad]'], + + ['und_mdir', 's', 'magn_meas', 'name of magnetic measurements sub-folder'], + ['und_mfs', 's', '', 'name of undulator magnetic measurements for different gaps summary file'], + ['und2_mfs', 's', '', 'name of second undulator magnetic measurements for different gaps summary file'], + + ['und_b2e', '', '', 'estimate undulator fundamental photon energy (in [eV]) for the amplitude of sinusoidal magnetic field defined by und_b or und_bx, und_by', 'store_true'], + ['und_e2b', '', '', 'estimate undulator field amplitude (in [T]) for the photon energy defined by w_e', 'store_true'], + +#---Calculation Types + #Electron Trajectory + ['tr', '', '', 'calculate electron trajectory', 'store_true'], + ['tr_cti', 'f', 0., 'initial time moment (c*t) for electron trajectory calculation [m]'], + ['tr_ctf', 'f', 0., 'final time moment (c*t) for electron trajectory calculation [m]'], + ['tr_np', 'f', 50000, 'number of points for trajectory calculation'], + ['tr_mag', 'i', 2, 'magnetic field to be used for trajectory calculation: 1- approximate, 2- accurate'], + ['tr_fn', 's', 'res_trj.dat', 'file name for saving calculated trajectory data'], + ['tr_pl', 's', 'xz,xpz,yz,ypz,xy,xpyp', 'plot the resulting trajectiry in graph(s): ""- dont plot, otherwise the string should list the trajectory components to plot'], + + #Single-Electron Spectrum vs Photon Energy + ['ss', '', '', 'calculate single-e spectrum vs photon energy', 'store_true'], + ['ss_ei', 'f', 100., 'initial photon energy [eV] for single-e spectrum vs photon energy calculation'], + ['ss_ef', 'f', 20000., 'final photon energy [eV] for single-e spectrum vs photon energy calculation'], + ['ss_ne', 'i', 10000, 'number of points vs photon energy for single-e spectrum vs photon energy calculation'], + ['ss_x', 'f', 0., 'horizontal position [m] for single-e spectrum vs photon energy calculation'], + ['ss_y', 'f', 0., 'vertical position [m] for single-e spectrum vs photon energy calculation'], + ['ss_meth', 'i', 1, 'method to use for single-e spectrum vs photon energy calculation: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler"'], + ['ss_prec', 'f', 0.01, 'relative precision for single-e spectrum vs photon energy calculation (nominal value is 0.01)'], + ['ss_zi', 'f', 0., 'initial longitudinal position along electron trajectory for SR spectrum calculation (effective if ss_zi < ss_zf)'], + ['ss_zf', 'f', 0., 'final longitudinal position along electron trajectory for SR spectrum calculation (effective if ss_zi < ss_zf)'], + ['ss_pol', 'i', 6, 'polarization component to extract after spectrum vs photon energy calculation: 0- Linear Horizontal, 1- Linear Vertical, 2- Linear 45 degrees, 3- Linear 135 degrees, 4- Circular Right, 5- Circular Left, 6- Total'], + ['ss_mag', 'i', 1, 'magnetic field to be used for single-e spectrum vs photon energy calculation: 1- approximate, 2- accurate'], + ['ss_ft', 's', 'f', 'presentation/domain: "f"- frequency (photon energy), "t"- time'], + ['ss_u', 'i', '1', 'electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time)'], + ['ss_fn', 's', 'res_spec_se.dat', 'file name for saving calculated single-e spectrum vs photon energy'], + ['ss_pl', 's', 'e', 'plot the resulting single-e spectrum in a graph: ""- dont plot, "e"- show plot vs photon energy'], + + #Coherent Gaussian Beam Spectrum vs Photon Energy or Time + ['gs', '', '', 'calculate Gaussian beam spectrum vs photon energy or time (has priority over "ss" if both Gaussian beam and e-beam + magnetic field are defined)', 'store_true'], + + #Multi-Electron Spectrum vs Photon Energy (taking into account e-beam emittance, energy spread and collection aperture size) + ['sm', '', '', 'calculate multi-e spectrum vs photon energy', 'store_true'], + ['sm_ei', 'f', 100., 'initial photon energy [eV] for multi-e spectrum vs photon energy calculation'], + ['sm_ef', 'f', 20000., 'final photon energy [eV] for multi-e spectrum vs photon energy calculation'], + ['sm_ne', 'i', 10000, 'number of points vs photon energy for multi-e spectrum vs photon energy calculation'], + ['sm_x', 'f', 0., 'horizontal center position [m] for multi-e spectrum vs photon energy calculation'], + ['sm_rx', 'f', 0.001, 'range of horizontal position / horizontal aperture size [m] for multi-e spectrum vs photon energy calculation'], + ['sm_nx', 'i', 1, 'number of points vs horizontal position for multi-e spectrum vs photon energy calculation'], + ['sm_y', 'f', 0., 'vertical center position [m] for multi-e spectrum vs photon energy calculation'], + ['sm_ry', 'f', 0.001, 'range of vertical position / vertical aperture size [m] for multi-e spectrum vs photon energy calculation'], + ['sm_ny', 'i', 1, 'number of points vs vertical position for multi-e spectrum vs photon energy calculation'], + ['sm_smpf', 'f', -1, 'sampling factor for calculation of intensity distribution vs horizontal and vertical position (active if >0)'], + ['sm_mag', 'i', 1, 'magnetic field to be used for calculation of multi-e spectrum spectrum or intensity distribution: 1- approximate, 2- accurate'], + ['sm_hi', 'i', 1, 'initial UR spectral harmonic to be taken into accountfor multi-e spectrum vs photon energy calculation'], + ['sm_hf', 'i', 15, 'final UR spectral harmonic to be taken into accountfor multi-e spectrum vs photon energy calculation'], + ['sm_prl', 'f', 1., 'longitudinal integration precision parameter for multi-e spectrum vs photon energy calculation'], + ['sm_pra', 'f', 1., 'azimuthal integration precision parameter for multi-e spectrum vs photon energy calculation'], + ['sm_meth', 'i', 1, 'method to use for spectrum vs photon energy calculation in case of arbitrary input magnetic field: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler", -1- dont use this accurate integration method (rather use approximate if possible)'], + ['sm_prec', 'f', 0.01, 'relative precision for spectrum vs photon energy calculation in case of arbitrary input magnetic field (nominal value is 0.01)'], + ['sm_nm', 'i', 1000000, 'number of macro-electrons for calculation of spectrum in case of arbitrary input magnetic field'], + ['sm_na', 'i', 10, 'number of macro-electrons to average on each node at parallel (MPI-based) calculation of spectrum in case of arbitrary input magnetic field'], + ['sm_ns', 'i', 10, 'saving periodicity (in terms of macro-electrons) for intermediate intensity at calculation of multi-electron spectrum in case of arbitrary input magnetic field'], + ['sm_type', 'i', 1, 'calculate flux (=1) or flux per unit surface (=2)'], + ['sm_pol', 'i', 6, 'polarization component to extract after calculation of multi-e flux or intensity: 0- Linear Horizontal, 1- Linear Vertical, 2- Linear 45 degrees, 3- Linear 135 degrees, 4- Circular Right, 5- Circular Left, 6- Total'], + ['sm_rm', 'i', 1, 'method for generation of pseudo-random numbers for e-beam phase-space integration: 1- standard pseudo-random number generator, 2- Halton sequences, 3- LPtau sequences (to be implemented)'], + ['sm_am', 'i', 0, 'multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance'], + ['sm_fn', 's', 'res_spec_me.dat', 'file name for saving calculated milti-e spectrum vs photon energy'], + ['sm_pl', 's', 'e', 'plot the resulting spectrum-e spectrum in a graph: ""- dont plot, "e"- show plot vs photon energy'], + + #Power Density Distribution vs horizontal and vertical position + ['pw', '', '', 'calculate SR power density distribution', 'store_true'], + ['pw_x', 'f', 0., 'central horizontal position [m] for calculation of power density distribution vs horizontal and vertical position'], + ['pw_rx', 'f', 0.015, 'range of horizontal position [m] for calculation of power density distribution vs horizontal and vertical position'], + ['pw_nx', 'i', 100, 'number of points vs horizontal position for calculation of power density distribution'], + ['pw_y', 'f', 0., 'central vertical position [m] for calculation of power density distribution vs horizontal and vertical position'], + ['pw_ry', 'f', 0.015, 'range of vertical position [m] for calculation of power density distribution vs horizontal and vertical position'], + ['pw_ny', 'i', 100, 'number of points vs vertical position for calculation of power density distribution'], + ['pw_pr', 'f', 1., 'precision factor for calculation of power density distribution'], + ['pw_meth', 'i', 1, 'power density computation method (1- "near field", 2- "far field")'], + ['pw_zi', 'f', 0., 'initial longitudinal position along electron trajectory for power density calculation (effective if pw_zi < pw_zf)'], + ['pw_zf', 'f', 0., 'final longitudinal position along electron trajectory for power density calculation (effective if pw_zi < pw_zf)'], + ['pw_mag', 'i', 1, 'magnetic field to be used for power density calculation: 1- approximate, 2- accurate'], + ['pw_fn', 's', 'res_pow.dat', 'file name for saving calculated power density distribution'], + ['pw_pl', 's', 'xy', 'plot the resulting power density distribution in a graph: ""- dont plot, "x"- vs horizontal position, "y"- vs vertical position, "xy"- vs horizontal and vertical position'], + + #Undulator "operation table", i.e. dependence of gap (and phase) on photon energy (for a given polarization) + ['ut', '', '', 'calculate undulator "operation table", i.e. dependence of gap (and phase) on photon energy (for a given polarization)', 'store_true'], + ['ut_fn', 's', 'und_oper_table.dat', 'file name for saving calculated undulator operation table data'], + + #Single-Electron Intensity distribution vs horizontal and vertical position + ['si', '', '', 'calculate single-e intensity distribution (without wavefront propagation through a beamline) vs horizontal and vertical position', 'store_true'], + + #Coherent Gaussian Beam Intensity distribution vs horizontal and vertical position + ['gi', '', '', 'calculate coherent Gaussian beam intensity distribution (without wavefront propagation through a beamline) vs horizontal and vertical position (has priority over "si" if both Gaussian beam and e-beam + magnetic field are defined)', 'store_true'], + + #Single-Electron Wavefront Propagation + ['ws', '', '', 'calculate single-electron (/ fully coherent) wavefront propagation', 'store_true'], + + #Coherent Gaussian Beam Wavefront Propagation + ['wg', '', '', 'calculate coherent Gaussian beam wavefront propagation (has priority over "si" if both Gaussian beam and e-beam + magnetic field are defined)', 'store_true'], + + #Multi-Electron (partially-coherent) Wavefront Propagation + ['wm', '', '', 'calculate multi-electron (/ partially coherent) wavefront propagation', 'store_true'], + + #General Wavefront parameters (used at several different calculations) + ['w_e', 'f', 9000., 'photon energy [eV] for calculation of intensity distribution vs horizontal and vertical position'], + ['w_ef', 'f', -1., 'final photon energy [eV] for calculation of intensity distribution vs horizontal and vertical position'], + ['w_ne', 'i', 1, 'number of points vs photon energy for calculation of intensity distribution'], + ['w_x', 'f', 0., 'central horizontal position [m] for calculation of intensity distribution'], + ['w_rx', 'f', 0.4e-03, 'range of horizontal position [m] for calculation of intensity distribution'], + ['w_nx', 'i', 100, 'number of points vs horizontal position for calculation of intensity distribution'], + ['w_y', 'f', 0., 'central vertical position [m] for calculation of intensity distribution vs horizontal and vertical position'], + ['w_ry', 'f', 0.6e-03, 'range of vertical position [m] for calculation of intensity distribution vs horizontal and vertical position'], + ['w_ny', 'i', 100, 'number of points vs vertical position for calculation of intensity distribution'], + ['w_smpf', 'f', 1., 'sampling factor for calculation of intensity distribution vs horizontal and vertical position'], + ['w_meth', 'i', 1, 'method to use for calculation of intensity distribution vs horizontal and vertical position: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler"'], + ['w_prec', 'f', 0.01, 'relative precision for calculation of intensity distribution vs horizontal and vertical position'], + ['w_zi', 'f', 0., 'initial longitudinal position [m] along electron trajectory for SR calculation (effective if w_zi < w_zf)'], + ['w_zf', 'f', 0., 'final longitudinal position [m] along electron trajectory for SR calculation (effective if w_zi < w_zf)'], + ['w_mag', 'i', 1, 'magnetic field to be used for calculation of intensity distribution vs horizontal and vertical position: 1- approximate, 2- accurate'], + ['w_ft', 's', 'f', 'presentation/domain: "f"- frequency (photon energy), "t"- time'], + ['w_u', 'i', '1', 'electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time)'], + ['w_wr', 'f', 0., 'wavefront radius to set (is taken into account if != 0) [m]; this parameter may be important for subsequent wavefront propagation simulations; by default, it is set by a function calculating the initial wavefront; however, it can also be set manually using this variable'], + ['w_wre', 'f', 0., 'wavefront radius error (is taken into account if != 0) [m]; this parameter may be important for subsequent wavefront propagation simulations; by default, it is set by a function calculating the initial wavefront; however, it can also be set manually using this variable'], + + ['si_pol', 'i', 6, 'polarization component to extract after calculation of intensity distribution: 0- Linear Horizontal, 1- Linear Vertical, 2- Linear 45 degrees, 3- Linear 135 degrees, 4- Circular Right, 5- Circular Left, 6- Total'], + ['si_type', 'i', 0, 'type of a characteristic to be extracted after calculation of intensity distribution: 0- Single-Electron Intensity, 1- Multi-Electron Intensity, 2- Single-Electron Flux, 3- Multi-Electron Flux, 4- Single-Electron Radiation Phase, 5- Re(E): Real part of Single-Electron Electric Field, 6- Im(E): Imaginary part of Single-Electron Electric Field, 7- Single-Electron Intensity, integrated over Time or Photon Energy'], + ['si_fn', 's', 'res_int_se.dat', 'file name for saving calculated single-e intensity distribution (without wavefront propagation through a beamline) vs horizontal and vertical position'], + + #['mi_pol', 'i', 6, 'polarization component: 0- Linear Horizontal, 1- Linear Vertical, 2- Linear 45 degrees, 3- Linear 135 degrees, 4- Circular Right, 5- Circular Left, 6- Total'], + #['mi_fn', 's', 'res_int_me.dat', 'file name for saving calculated multi-e intensity distribution (without wavefront propagation through a beamline) vs horizontal and vertical position, for one or several photon energies'], + + ['ws_fne', 's', '', 'file name for saving initial electric field wavefront (before propagation)'], + ['ws_fnep', 's', '', 'file name for saving electric field wavefront after propagation'], + ['ws_fnei', 's', '', 'file name for input electric field for further eventual propagation; if this file name is supplied, the initial electric field will not be calculated, but loaded from this file'], + ['ws_fni', 's', 'res_int_pr_se.dat', 'file name for saving propagated single-e intensity distribution vs horizontal and vertical position'], + + ['ws_pl', 's', 'xy', 'plot the propagated radiaiton intensity distributions in graph(s): ""- dont plot, "x"- vs horizontal position, "y"- vs vertical position, "xy"- vs horizontal and vertical position'], + ['ws_ap', 'i', 0, 'switch specifying representation of the resulting Stokes parameters (/ Intensity distribution): coordinate (0) or angular (1)'], + ['si_pl', 's', 'xy', 'plot the input intensity distributions in graph(s): ""- dont plot, "x"- vs horizontal position, "y"- vs vertical position, "xy"- vs horizontal and vertical position'], + + ['wm_nm', 'i', 100000, 'number of macro-electrons (coherent wavefronts) for calculation of multi-electron wavefront propagation'], + ['wm_na', 'i', 5, 'number of macro-electrons (coherent wavefronts) to average on each node at parallel (MPI-based) calculation of multi-electron wavefront propagation'], + ['wm_ns', 'i', 5, 'saving periodicity (in terms of macro-electrons / coherent wavefronts) for intermediate intensity at multi-electron wavefront propagation calculation'], + ['wm_ch', 'i', 0, 'type of a characteristic to be extracted after calculation of multi-electron wavefront propagation: #0- intensity (s0); 1- four Stokes components; 2- mutual intensity cut vs x; 3- mutual intensity cut vs y'], + ['wm_ap', 'i', 0, 'switch specifying representation of the resulting Stokes parameters: coordinate (0) or angular (1)'], + ['wm_x0', 'f', 0, 'horizontal center position for mutual intensity cut calculation'], + ['wm_y0', 'f', 0, 'vertical center position for mutual intensity cut calculation'], + ['wm_ei', 'i', 0, 'integration over photon energy is required (1) or not (0); if the integration is required, the limits are taken from w_e, w_ef'], + ['wm_rm', 'i', 1, 'method for generation of pseudo-random numbers for e-beam phase-space integration: 1- standard pseudo-random number generator, 2- Halton sequences, 3- LPtau sequences (to be implemented)'], + ['wm_am', 'i', 0, 'multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance'], + ['wm_fni', 's', 'res_int_pr_me.dat', 'file name for saving propagated multi-e intensity distribution vs horizontal and vertical position'], + + #['ws_fn', 's', '', 'file name for saving single-e (/ fully coherent) wavefront data'], + #['wm_fn', 's', '', 'file name for saving multi-e (/ partially coherent) wavefront data'], + + #Optics parameters + ['op_r', 'f', 30., 'longitudinal position of the first optical element [m]'], + ['op_dp', 'f', 0., 'length of drift space to be applied after propagation through a beamline [m]'], + + #Detector parameters + ['d_x', 'f', 0., 'central horizontal position [m] of detector active area'], + ['d_rx', 'f', 0., 'range of horizontal position [m] of detector active area (should be >0 to be taken into account)'], + ['d_nx', 'i', 0, 'number of pixels vs horizontal position (should be >0 to be taken into account)'], + ['d_dx', 'f', 0., 'horizontal size of pixel [m]'], + ['d_y', 'f', 0., 'central vertical position [m] of detector active area'], + ['d_ry', 'f', 0., 'range of vertical position [m] of detector active area (should be >0 to be taken into account)'], + ['d_ny', 'i', 0, 'number of pixels vs vertical position (should be >0 to be taken into account)'], + ['d_dy', 'f', 0., 'vertical size of pixel [m]'], + ['d_or', 'f', 1, 'interpolation order (i.e. order of polynomials to be used at 2D interpolation)'], + ['d_ifn', 's', '', 'file name with detector spectral efficiency data (on 1D mesh vs photon energy: _eStart, _eFin, _ne)'], + #['d_ifn', 's', 'in_det_spec_eff.dat', 'file name with detector spectral efficiency data (on 1D mesh vs photon energy: _eStart, _eFin, _ne)'], + + #to add options + ] + return varParamStd + +#**************************************************************************** +def srwl_uti_merge_options(_arOpt1, _arOpt2): + """Merge arrays of options specified in _arOpt1 and _arOpt2, eliminating duplicates + :param _arOpt1: list providing compact description of options; every element of this list is supposed to contain: + [0]: string containing option (/ variable) name + [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) + [2]: default value + [3]: string containing help / explanation of the option / variable + [4]: optional string describing formal action to be taken if option is fired + :param _arOpt2: list providing compact description of extra options + """ + nOpt1 = len(_arOpt1) + nOpt2 = len(_arOpt2) + arOptRes = copy(_arOpt1) + + for i in range(nOpt2): + curOpt2 = _arOpt2[i] + curOpt2nm = curOpt2[0] + iOpt1 = nOpt1 + for j in range(nOpt1): + curOpt1 = arOptRes[j] + curOpt1nm = curOpt1[0] + if(curOpt2nm == curOpt1nm): + iOpt1 = j + break + curOpt2c = copy(curOpt2) + if((iOpt1 >= 0) and (iOpt1 < nOpt1)): + arOptRes[iOpt1] = curOpt2c + else: + arOptRes.append(curOpt2c) + return arOptRes + +#**************************************************************************** +def srwl_uti_ext_options(_arOpt): + """Extend array of standard options with the options specified in _arOpt, eliminating duplicates + :param _arOpt: list providing compact description of extra options; every element of this list is supposed to contain: + [0]: string containing option (/ variable) name + [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) + [2]: default value + [3]: string containing help / explanation of the option / variable + [4]: optional string describing formal action to be taken if option is fired + """ + return srwl_uti_merge_options(srwl_uti_std_options(), _arOpt) + +#**************************************************************************** +##def srwl_uti_parse_options(_descr): #OC08032016 (commented-out) +## """Set and parse command-prompt options from a compact description provided in _descr +## :param _descr: list providing compact description of all options; every element of this list is supposed to contain: +## [0]: string containing option (/ variable) name +## [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) +## [2]: default value +## [3]: string containing help / explanation of the option / variable +## [4]: optional string describing formal action to be taken if option is fired +## """ +## +## p = optparse.OptionParser() +## nOpt = len(_descr) +## +## listOptNamesPostParse = [] +## for i in range(nOpt): +## curOpt = _descr[i] +## +## sTypeShort = curOpt[1] +## sType = 'string' +## if(sTypeShort == 'f'): sType = 'float' +## elif(sTypeShort == 'i'): sType = 'int' +## #elif(sTypeShort == 's'): sType = 'string' +## +## sAct = 'store' +## if(len(curOpt) > 4): sAct = curOpt[4] +## +## defVal = curOpt[2] +## +## optIsList = False +## if(isinstance(defVal, list) or isinstance(defVal, array)): optIsList = True +## +## if(optIsList): +## sType = 'string' +## listOptNamesPostParse.append(curOpt[0]) +## +## if(len(sTypeShort) <= 0): +## p.add_option('--' + curOpt[0], default=defVal, help=curOpt[3], action=sAct) +## else: +## p.add_option('--' + curOpt[0], type=sType, default=defVal, help=curOpt[3], action=sAct) +## +## v, args = p.parse_args() +## +## #"post-parsing" list-type options +## for i in range(len(listOptNamesPostParse)): +## curOptName = listOptNamesPostParse[i] +## valCurOpt = getattr(v, curOptName) +## +## if((isinstance(valCurOpt, list) == False) and (isinstance(valCurOpt, array) == False)): +## parsedVal = srwl_uti_parse_str2list(valCurOpt) +## setattr(v, curOptName, parsedVal) +## +## return v + +#**************************************************************************** +#def _optparse(_descr, use_sys_argv=True, args=None): #MR26022016, MR04032016 +def srwl_uti_parse_options_obs(_descr, use_sys_argv=True, args=None): #OC08032016 #MR26022016, MR04032016 + """Set and parse command-prompt options from a compact description provided in _descr using optparse (OBSOLETE: deprecated since Python 2.7). + :param _descr: list providing compact description of all options; every element of this list is supposed to contain: + [0]: string containing option (/ variable) name + [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) + [2]: default value + [3]: string containing help / explanation of the option / variable + [4]: optional string describing formal action to be taken if option is fired + :param use_sys_argv: a flag which manages use of sys.argv values in optparse. + :param args: arbitrary arguments to be parsed, used when use_sys_argv is set to False. + """ + import optparse + + p = optparse.OptionParser(None if use_sys_argv else __name__) + nOpt = len(_descr) + + listOptNamesPostParse = [] + for i in range(nOpt): + curOpt = _descr[i] + + sTypeShort = curOpt[1] + sType = 'string' + if (sTypeShort == 'f'): + sType = 'float' + elif (sTypeShort == 'i'): + sType = 'int' + # elif(sTypeShort == 's'): sType = 'string' + + sAct = 'store' + if (len(curOpt) > 4): sAct = curOpt[4] + + defVal = curOpt[2] + + optIsList = False + if (isinstance(defVal, list) or isinstance(defVal, array)): optIsList = True + + if (optIsList): + sType = 'string' + listOptNamesPostParse.append(curOpt[0]) + + if (len(sTypeShort) <= 0): + p.add_option('--' + curOpt[0], default=defVal, help=curOpt[3], action=sAct) + else: + p.add_option('--' + curOpt[0], type=sType, default=defVal, help=curOpt[3], action=sAct) + + #MR07032016: + if use_sys_argv: + v, args = p.parse_args() #MR07032016 + else: + try: + v, args = p.parse_args(args if args else []) #MR07032016 + except SystemExit as e: + raise ValueError('Exit code: {}'.format(e)) + + # "post-parsing" list-type options + for i in range(len(listOptNamesPostParse)): + curOptName = listOptNamesPostParse[i] + valCurOpt = getattr(v, curOptName) + + if ((isinstance(valCurOpt, list) == False) and (isinstance(valCurOpt, array) == False)): + parsedVal = srwl_uti_parse_str2list(valCurOpt) + setattr(v, curOptName, parsedVal) + + return v + +#**************************************************************************** +#def _argparse(_descr, use_sys_argv=True, args=None): #MR26022016, MR04032016 +def srwl_uti_parse_options(_descr, use_sys_argv=True, args=None): #OC08032016 #MR26022016, MR04032016 + """Set and parse command-prompt options from a compact description provided in _descr using argparse (recommended since Python 2.7). + :param _descr: list providing compact description of all options; every element of this list is supposed to contain: + [0]: string containing option (/ variable) name + [1]: string containing type of the option / variable ('f' - float, 'i' - integer, 's' - string) + [2]: default value + [3]: string containing help / explanation of the option / variable + [4]: optional string describing formal action to be taken if option is fired + :param use_sys_argv: a flag which manages use of sys.argv values in argparse. + :param args: arbitrary arguments to be parsed, used when use_sys_argv is set to False. + """ + import argparse + + #_descr = srwl_uti_ext_options(deepcopy(_descr)) #OCTEST: consider adding this? + + p = argparse.ArgumentParser(None if use_sys_argv else __name__) #MR07032016 + nOpt = len(_descr) + + listOptNamesPostParse = [] + for i in range(nOpt): + curOpt = _descr[i] + + sTypeShort = curOpt[1] + sType = str + if sTypeShort == 'f': + sType = float + elif sTypeShort == 'i': + sType = int + + sAct = 'store' + if (len(curOpt) > 4): sAct = curOpt[4] + + defVal = curOpt[2] + + optIsList = False + if (isinstance(defVal, list) or isinstance(defVal, array)): optIsList = True + + if (optIsList): + sType = str + listOptNamesPostParse.append(curOpt[0]) + + #curOpt[3] = curOpt[3].replace('%', '%%') # screen special '%' symbol + if '%%' not in curOpt[3]: #MR14042018 (via GitHub pull req.) + curOpt[3] = curOpt[3].replace('%', '%%') # screen special '%' symbol + + if (len(sTypeShort) <= 0): + p.add_argument('--' + curOpt[0], default=defVal, help=curOpt[3], action=sAct) + else: + p.add_argument('--' + curOpt[0], type=sType, default=defVal, help=curOpt[3], action=sAct) + + #MR07032016: + if use_sys_argv: + v = p.parse_args() #MR07032016 + else: + try: + v = p.parse_args(args if args else []) #MR07032016 + except SystemExit as e: + raise ValueError('Exit code: {}'.format(e)) + + # "post-parsing" list-type options + for i in range(len(listOptNamesPostParse)): + curOptName = listOptNamesPostParse[i] + valCurOpt = getattr(v, curOptName) + + if not isinstance(valCurOpt, list) and not isinstance(valCurOpt, array): #MR07032016 + parsedVal = srwl_uti_parse_str2list(valCurOpt) + setattr(v, curOptName, parsedVal) + + return v + +''' +MR26022016: Here we can specify which parser to use for parsing the options. Argparse is used by default, but if +a user wants to execute optparse, the following environment variable has to be set up: + SRWL_OPTPARSE=1 + +On Linux systems it can be set either in ~/.bashrc using: + export SRWL_OPTPARSE=1 +or just before the executed command: + SRWL_OPTPARSE=1 python script.py -h + +On Windows systems it can be set using "Environment Variables..." button in System Properties or via command line: + set SRWL_OPTPARSE=1 + +If you wish to use a particular parser, edit the statement below as follows: + srwl_uti_parse_options = _optparse # for optparse + srwl_uti_parse_options = _argparse # for argparse + +Various options can be specified including lists, e.g.: + python script.py --op_S0_pp="[0, 0, 1, 0, 0, 5.0, 8.0, 2.5, 3.5, 0, 0, 0]" +''' + +#srwl_uti_parse_options = srwl_uti_parse_options_obs if os.getenv('SRWL_OPTPARSE') else _argparse # MR07032016 +if(os.getenv('SRWL_OPTPARSE')): #OC08032016 + srwl_uti_parse_options = srwl_uti_parse_options_obs + +#**************************************************************************** +#OC: This function function may need to be moved to SRWLBeamline class or renamed (to have name with prefixes / "decorations") +def setup_source(v): #MR20160617 - moved from Sirepo .jinja template + mag = None + if v.source_type in ['u', 't']: + if v.source_type == 'u' or (not v.und_g or v.und_g == 0): + v.und_b = 1 + if hasattr(v, 'und_g'): + del v.und_g + if hasattr(v, 'gbm_pen'): + del v.gbm_pen + elif v.source_type == 't' or (v.und_g and v.und_g > 0): + if hasattr(v, 'gbm_pen'): + del v.gbm_pen + v.pw_mag = 2 + v.w_mag = 2 + elif v.source_type == 'g': + pass + elif v.source_type == 'm': + mag = SRWLMagFldC() + mag.arXc.append(0) + mag.arYc.append(0) + mag.arMagFld.append(SRWLMagFldM( + v.mp_field, + v.mp_order, + v.mp_distribution, + v.mp_len + )) + mag.arZc.append(v.mp_zc) + if hasattr(v, 'gbm_pen'): + del v.gbm_pen + else: + raise AssertionError('{}: unknown source_type'.format(v.source_type)) + + return v.source_type, mag + diff --git a/env/release/srw_python/srwl_uti_cryst.py b/env/release/srw_python/srwl_uti_cryst.py new file mode 100644 index 00000000..1f5f1098 --- /dev/null +++ b/env/release/srw_python/srwl_uti_cryst.py @@ -0,0 +1,272 @@ +############################################################################# +# SRWLib for Python Utility module for Crystal Optics +# Author: A. Suvorov, O.C. +# v 0.01 +############################################################################# + +from math import * +import cmath + +strMatDataNotDefined = 'The data for this crystal material is not defined (yet).' + +#**************************************************************************** +#def SiASF(s): # calculates Si atomic scattering factor +def srwl_uti_cryst_ASF(_s, _mat='Si'): + """Calculates Atomic Scattering Factor for some crystal materials + :param _s: + :param _mat: crystal material + """ + fa = None + fa0 = 0 + if(_mat == 'Si'): + fa = [6.2915,2.4386,3.0353,32.3337,1.9891,0.6785,1.541,81.6937,1.1407] + fa0 = 13.985 + #to extend this for other crystal materials here + else: raise Exception(strMatDataNotDefined) + + s2 = _s*_s ; + if s2 != 0: + f0 = fa[0]*exp(-fa[1]*s2) + fa[2]*exp(-fa[3]*s2) + fa[4]*exp(-fa[5]*s2) + fa[6]*exp(-fa[7]*s2) + fa[8] + else: + f0 = fa0 + return f0 + +#**************************************************************************** +#def SiPlaneSpace(Hr): +def srwl_uti_cryst_pl_sp(_hr=None, _mat='Si'): + """Calculates reflecting planes distance + :param _hr: Miller's indices of reflection + :param _mat: crystal material + """ + + d = None + if(_mat == 'Si'): d = 5.43096890 # Si lattice constant (A) + #to extend this for other crystal materials here + else: raise Exception(strMatDataNotDefined) + + #return d/norm(Hr) + if(_hr is None): return d + else: return d/sqrt(sum(n*n for n in _hr)) + +#**************************************************************************** +#def FourierPolarCompon(En,Hr): +def srwl_uti_cryst_pol_f(_en, _hr, _mat='Si'): + """Calculates Fourier components of Si polarizability + :param _en: energy [eV] of reflection + :param _hr: Miller's indices of reflection + :param _mat: crystal material + :return [psi0r, psi0i, psiHr, psiHi]: + psi0r, psi0i - real and imaginary parts of the 0-th Fourier components + psiHr, psiHi - real and imaginary parts of the H-th Fourier components + """ + + # Linear interpolation (for anomalous scattering factors) + # could be improved, taking into account that the table is monotonous + def interp_f1f2(x, y1, y2, z): + for xn in x: + if xn >= z: break + nn = x.index(xn) + f1 = None; f2 = None + if nn > 0 & nn < len(x): + dE = x[nn] - x[nn-1] + dF1 = y1[nn] - y1[nn-1] + dF2 = y2[nn] - y2[nn-1] + f1 = y1[nn-1] + (z-x[nn-1])*dF1/dE + f2 = y2[nn-1] + (z-x[nn-1])*dF2/dE + else: raise Exception('Argument is out of range of existing tabulated data') + return [f1, f2] + + # Vector length + #def norm(_a): return sqrt(sum(n*n for n in _a)) + + # Constants + re = 2.8179402894e-5 # classical radius of electron (A) + eV2wA = 12398.4193009 # energy to wavelength conversion factor 12398.41930092394 + + cDW = None + rCell = None + xE = None + ff1 = None + ff2 = None + + if(_mat == 'Si'): + cDW = 0.5 # Debye-Waller constant for Si + rCell = [[0.,0.,0.],[0.5,0.5,0.],[0.5,0.,0.5],[0.,0.5,0.5],[0.25,0.25,0.25], + [0.75,0.75,0.25],[0.75,0.25,0.75],[0.25,0.75,0.75]] # coordinates of atoms in Si cell + + # Tabulated parameters: + # Photon Energy [eV] against which material-dependent parameters are tabulated (move to general, and use this mesh for all materials?) + xE = [1000,1100,1200,1300,1400,1500,1600,1700,1741,1746,1751,1756,1761,1766,1771,1776,1781,1786, + 1791,1796,1800,1801,1806,1811,1816,1821,1826,1831,1836,1841,1846,1851,1856,1861,1866,1871, + 1876,1881,1886,1891,1896,1900,1901,1906,1911,1916,1921,1926,1931,1936,2000,2100,2200,2300, + 2400,2500,2600,2700,2800,2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100, + 4200,4300,4400,4500,4600,4700,4800,4900,5000,5100,5200,5300,5400,5500,5600,5700,5800,5900, + 6000,6100,6200,6300,6400,6500,6600,6700,6800,6900,7000,7100,7200,7300,7400,7500,7600,7700, + 7800,7900,8000,8100,8200,8300,8400,8500,8600,8700,8800,8900,9000,9100,9200,9300,9400,9500, + 9600,9700,9800,9900,10000,10100,10200,10300,10400,10500,10600,10700,10800,10900,11000,11100, + 11200,11300,11400,11500,11600,11700,11800,11900,12000,12100,12200,12300,12400,12500,12600, + 12700,12800,12900,13000,13100,13200,13300,13400,13500,13600,13700,13800,13900,14000,14100, + 14200,14300,14400,14500,14600,14700,14800,14900,15000,15100,15200,15300,15400,15500,15600, + 15700,15800,15900,16000,16100,16200,16300,16400,16500,16600,16700,16800,16900,17000,17100, + 17200,17300,17400,17500,17600,17700,17800,17900,18000,18100,18200,18300,18400,18500,18600, + 18700,18800,18900,19000,19100,19200,19300,19400,19500,19600,19700,19800,19900,20000,20100, + 20200,20300,20400,20500,20600,20700,20800,20900,21000,21100,21200,21300,21400,21500,21600, + 21700,21800,21900,22000,22100,22200,22300,22400,22500,22600,22700,22800,22900,23000,23100, + 23200,23300,23400,23500,23600,23700,23800,23900,24000,24100,24200,24300,24400,24500,24600, + 24700,24800,24900,25000,25100,25200,25300,25400,25500,25600,25700,25800,25900,26000,26100, + 26200,26300,26400,26500,26600,26700,26800,26900,27000,27100,27200,27300,27400,27500,27600, + 27700,27800,27900,28000,28100,28200,28300,28400,28500,28600,28700,28800,28900,29000,29100, + 29200,29300,29400,29500,29600,29700,29800,29900,30000,30100,30200,30300,30400,30500,30600, + 30700,30800,30900,31000,31100,31200,31300,31400,31500,31600,31700,31800,31900,32000,32100, + 32200,32300,32400,32500,32600,32700,32800,32900,33000,33100,33200,33300,33400,33500,33600, + 33700,33800,33900,34000,34100,34200,34300,34400,34500,34600,34700,34800,34900,35000,35100, + 35200,35300,35400,35500,35600,35700,35800,35900,36000,36100,36200,36300,36400,36500,36600, + 36700,36800,36900,37000,37100,37200,37300,37400,37500,37600,37700,37800,37900,38000,38100, + 38200,38300,38400,38500,38600,38700,38800,38900,39000,39100,39200,39300,39400,39500,39600, + 39700,39800,39900,40000,40100,40200,40300,40400,40500,40600,40700,40800,40900,41000,41100, + 41200,41300,41400,41500,41600,41700,41800,41900,42000,42100,42200,42300,42400,42500,42600, + 42700,42800,42900,43000,43100,43200,43300,43400,43500,43600,43700,43800,43900,44000,44100, + 44200,44300,44400,44500,44600,44700,44800,44900,45000,45100,45200,45300,45400,45500,45600, + 45700,45800,45900,46000,46100,46200,46300,46400,46500,46600,46700,46800,46900,47000,47100, + 47200,47300,47400,47500,47600,47700,47800,47900,48000,48100,48200,48300,48400,48500,48600, + 48700,48800,48900,49000,49100,49200,49300,49400,49500,49600,49700,49800,49900,50000] + ff1 = [-1.1591,-1.2797,-1.4121,-1.5632,-1.7439,-1.9743,-2.2963,-2.8244,-3.1832,-3.2381,-3.2963, + -3.3582,-3.4243,-3.4952,-3.5716,-3.6542,-3.7442,-3.843,-3.9522,-4.0743,-4.1833,-4.2124, + -4.3712,-4.5574,-4.7822,-5.0647,-5.4435,-6.0156,-7.1968,-7.5667,-6.094,-5.4422,-5.0152, + -4.6955,-4.441,-4.2263,-4.0413,-3.8785,-3.7329,-3.6011,-3.4805,-3.3909,-3.3693,-3.266, + -3.1696,-3.079,-2.9937,-2.9129,-2.8362,-2.7632,-2.0432,-1.3246,-0.83998,-0.49318,-0.41208, + -0.24945,-0.12251,-0.021709,0.057712,0.12383,0.17836,0.22264,0.25882,0.28838,0.31246, + 0.33201,0.34776,0.35877,0.36854,0.37608,0.38173,0.3858,0.3885,0.39006,0.39064,0.39039, + 0.38943,0.38786,0.38579,0.38328,0.3804,0.37722,0.37367,0.37001,0.36618,0.36219,0.35809, + 0.3539,0.34963,0.34532,0.34096,0.33659,0.3322,0.32781,0.32343,0.31906,0.31472,0.31041, + 0.30614,0.3019,0.2977,0.29355,0.28945,0.28539,0.28139,0.27744,0.27355,0.2697,0.26592, + 0.26219,0.25615,0.25254,0.249,0.24551,0.24208,0.23871,0.23539,0.23213,0.22893,0.22578, + 0.22266,0.21959,0.21658,0.21362,0.21071,0.20786,0.20505,0.20229,0.1995,0.19693,0.19432, + 0.19175,0.18923,0.18675,0.18432,0.18192,0.17957,0.17726,0.17499,0.17276,0.17057,0.16842, + 0.1663,0.16421,0.16217,0.16015,0.15817,0.15623,0.15431,0.15243,0.15058,0.14876,0.14696, + 0.1452,0.14347,0.14176,0.14008,0.13843,0.1368,0.1352,0.13363,0.13208,0.13055,0.12905, + 0.12757,0.12612,0.12468,0.12327,0.12188,0.12051,0.11916,0.11783,0.11652,0.11523,0.11396, + 0.11271,0.11148,0.11026,0.10906,0.10788,0.10672,0.10557,0.10444,0.10332,0.10222,0.10114, + 0.10007,0.099018,0.097978,0.096953,0.095942,0.094945,0.093961,0.092991,0.092034,0.091089, + 0.090157,0.089238,0.08833,0.087435,0.086551,0.085679,0.084818,0.083968,0.083129,0.082301, + 0.081484,0.080677,0.07988,0.079093,0.078316,0.077548,0.076791,0.076042,0.075303,0.074573, + 0.073851,0.073139,0.072435,0.07174,0.071053,0.070374,0.069703,0.06904,0.068386,0.067738, + 0.067099,0.066466,0.065842,0.065224,0.064613,0.06401,0.063413,0.062823,0.06224,0.061664, + 0.061093,0.06053,0.059972,0.059421,0.058876,0.058337,0.057803,0.057276,0.056754,0.056238, + 0.055728,0.055223,0.054723,0.054229,0.05374,0.053256,0.052777,0.052304,0.051835,0.051371, + 0.050912,0.050458,0.050008,0.049563,0.049123,0.048687,0.048255,0.047828,0.047405,0.046986, + 0.046572,0.046161,0.045755,0.045353,0.044954,0.04456,0.044169,0.043782,0.043399,0.04302, + 0.042644,0.042272,0.041903,0.041538,0.041185,0.040828,0.040475,0.040125,0.039778,0.039435, + 0.039095,0.038758,0.038424,0.038094,0.037766,0.037442,0.037121,0.036803,0.036488,0.036176, + 0.035866,0.03556,0.035256,0.034956,0.034658,0.034363,0.03407,0.033781,0.033494,0.033209, + 0.032927,0.032648,0.032371,0.032097,0.031826,0.031557,0.03129,0.031025,0.030764,0.030504, + 0.030247,0.029992,0.029739,0.029489,0.029241,0.028995,0.028751,0.02851,0.028271,0.028033, + 0.027798,0.027565,0.027334,0.027105,0.026878,0.026654,0.026431,0.02621,0.025991,0.025774, + 0.025558,0.025345,0.025134,0.024924,0.024716,0.024511,0.024306,0.024104,0.023903,0.023705, + 0.023507,0.023312,0.023118,0.022926,0.022736,0.022547,0.02236,0.022174,0.021991,0.021808, + 0.021627,0.021448,0.021271,0.021094,0.02092,0.020747,0.020575,0.020405,0.020236,0.020069, + 0.019903,0.019738,0.019575,0.019413,0.019253,0.019094,0.018937,0.01878,0.018625,0.018472, + 0.018319,0.018168,0.018019,0.01787,0.017723,0.017577,0.017432,0.017288,0.017146,0.017005, + 0.016865,0.016726,0.016589,0.016452,0.016317,0.016183,0.01605,0.015918,0.015787,0.015657, + 0.015528,0.015401,0.015274,0.015149,0.015024,0.014901,0.014779,0.014657,0.014537,0.014418, + 0.014299,0.014182,0.014066,0.01395,0.013836,0.013723,0.01361,0.013498,0.013388,0.013278, + 0.013169,0.013061,0.012954,0.012848,0.012743,0.012638,0.012535,0.012432,0.01233,0.012229, + 0.012129,0.01203,0.011932,0.011834,0.011737,0.011641,0.011546,0.011451,0.011357,0.011265, + 0.011172,0.011081,0.01099,0.0109,0.010811,0.010723,0.010635,0.010548,0.010462,0.010376, + 0.010292,0.010207,0.010124,0.010041,0.0099592,0.0098778,0.0097971,0.009717,0.0096376, + 0.0095589,0.0094808,0.0094033,0.0093265,0.0092503,0.0091747,0.0090998,0.0090254,0.0089517, + 0.0088786,0.0088061,0.0087342,0.0086628,0.0085921,0.0085219,0.0084524,0.0083833,0.0083149, + 0.008247,0.0081797,0.0081129,0.0080467,0.7981,0.0079158,0.0078512,0.0077871,0.0077236, + 0.0076606,0.007598,0.007536,0.0074745,0.0074135,0.007353,0.007293,0.0072335,0.0071745, + 0.007116,0.0070579,0.0070003,0.0069432,0.0068866,0.0068304,0.0067747,0.0067194,0.0066646, + 0.0066102,0.0065563,0.0065028,0.0064498,0.0063972,0.006345,0.0062932,0.0062419,0.006191, + 0.0061405,0.0060904,0.0060408,0.0059915,0.0059426,0.0058942,0.0058461,0.0057984,0.0057512, + 0.0057043,0.0056577,0.0056116,0.0055659,0.0055205,0.0054755,0.0054308,0.0053865,0.0053426, + 0.0052991,0.0052559,0.005213,0.0051705] + ff2 = [0.97954,0.83919,0.72758,0.63724,0.56302,0.50123,0.44921,0.40497,0.38872,0.38681,0.38491, + 0.38302,0.38115,0.37929,0.37745,0.37562,0.3738,0.372,0.37021,0.36843,0.36701,0.36666,0.36491, + 0.36317,0.36144,0.35973,0.35803,0.35634,0.35466,4.1077,4.0995,4.0912,4.0827,4.0741,4.0654, + 4.0566,4.0476,4.0386,4.0294,4.0201,4.0107,4.0031,4.0012,3.9916,3.9819,3.972,3.9621,3.9521, + 3.942,3.9318,3.7934,3.5549,3.2999,3.0383,2.7847,2.6079,2.4484,2.3038,2.1723,2.0524,1.9427, + 1.84,1.7452,1.6573,1.5759,1.5002,1.4297,1.364,1.3029,1.2458,1.1923,1.1421,1.095,1.0507, + 1.009,0.96971,0.93263,0.8976,0.86448,0.83312,0.8034,0.77522,0.74846,0.72304,0.69886, + 0.67584,0.65392,0.63302,0.61308,0.59405,0.57586,0.55848,0.54184,0.52592,0.51067,0.49606, + 0.48204,0.46859,0.45568,0.44328,0.43136,0.4199,0.40888,0.39827,0.38805,0.37821,0.36872, + 0.35957,0.35075,0.34223,0.33404,0.32619,0.31861,0.31128,0.30419,0.29734,0.29071,0.28429, + 0.27808,0.27206,0.26625,0.26061,0.25515,0.24986,0.24473,0.23975,0.23491,0.23022,0.22567, + 0.22124,0.21694,0.21277,0.20871,0.20476,0.20092,0.19719,0.19355,0.19002,0.18657,0.18322, + 0.17995,0.17677,0.17367,0.17065,0.16771,0.16484,0.16204,0.15931,0.15664,0.15404,0.15151, + 0.14903,0.14661,0.14425,0.14195,0.13969,0.13749,0.13534,0.13324,0.13118,0.12917,0.12721, + 0.12529,0.12341,0.12157,0.11977,0.11801,0.11629,0.1146,0.11295,0.11133,0.10975,0.10819, + 0.10667,0.10519,0.10373,0.1023,0.1009,0.099522,0.098175,0.096854,0.095559,0.09429,0.093044, + 0.091822,0.090623,0.089447,0.088293,0.08716,0.086048,0.084957,0.083885,0.082833,0.0818, + 0.080786,0.079789,0.078811,0.077849,0.076905,0.075976,0.075064,0.074168,0.073287,0.072422, + 0.07157,0.070734,0.069911,0.069102,0.068307,0.067524,0.066755,0.065998,0.065253,0.064521, + 0.0638,0.063091,0.062393,0.061707,0.061031,0.060366,0.059711,0.059066,0.058431,0.057807, + 0.057191,0.056585,0.055989,0.055401,0.054822,0.054252,0.05369,0.053137,0.052592,0.052055, + 0.051525,0.051004,0.05049,0.049983,0.049484,0.048992,0.048507,0.048028,0.047557,0.047092, + 0.046634,0.046182,0.045736,0.045296,0.044863,0.044435,0.044013,0.043597,0.043187,0.042782, + 0.042383,0.041989,0.0416,0.041216,0.040837,0.040464,0.040095,0.039731,0.039371,0.039017, + 0.038667,0.038321,0.03798,0.037643,0.037311,0.036982,0.036658,0.036338,0.036022,0.035709, + 0.035401,0.035096,0.034796,0.034498,0.034205,0.033915,0.033602,0.033316,0.033033,0.032754, + 0.032477,0.032204,0.031933,0.031666,0.031402,0.03114,0.030882,0.030626,0.030373,0.030123, + 0.029875,0.02963,0.029388,0.029148,0.028911,0.028676,0.028444,0.028214,0.027987,0.027762, + 0.027539,0.027318,0.0271,0.026884,0.02667,0.026458,0.026248,0.02604,0.025835,0.025631, + 0.02543,0.02523,0.025033,0.024837,0.024643,0.024451,0.024261,0.024072,0.023886,0.023701, + 0.023518,0.023337,0.023157,0.022979,0.022803,0.022628,0.022455,0.022283,0.022113,0.021945, + 0.021778,0.021613,0.021449,0.021286,0.021125,0.020966,0.020808,0.020651,0.020495,0.020341, + 0.020189,0.020037,0.019887,0.019739,0.019591,0.019445,0.0193,0.019157,0.019014,0.018873, + 0.018733,0.018594,0.018457,0.01832,0.018185,0.01805,0.017917,0.017785,0.017654,0.017525, + 0.017396,0.017268,0.017142,0.017016,0.016891,0.016768,0.016645,0.016524,0.016403,0.016284, + 0.016165,0.016047,0.015931,0.015815,0.0157,0.015586,0.015473,0.015361,0.01525,0.015139, + 0.01503,0.014921,0.014813,0.014706,0.0146,0.014495,0.01439,0.014287,0.014184,0.014082, + 0.013981,0.01388,0.01378,0.013682,0.013583,0.013486,0.013389,0.013293,0.013198,0.013104, + 0.01301,0.012917,0.012825,0.012733,0.012642,0.012552,0.012462,0.012373,0.012285,0.012198, + 0.012111,0.012025,0.011939,0.011854,0.01177,0.011686,0.011603,0.011521,0.011439,0.011358, + 0.011277,0.011197,0.011118,0.011039,0.01096,0.010883,0.010806,0.010729,0.010653,0.010578, + 0.010503,0.010429,0.010355,0.010282,0.010209,0.010137,0.010065,0.0099943,0.0099238, + 0.0098537,0.0097842,0.0097151,0.0096466,0.0095786,0.0095111,0.009444,0.0093775,0.0093114, + 0.0092458,0.0091807,0.009116,0.0090518,0.0089881,0.0089249,0.0088621,0.0087997,0.0087378, + 0.0086764,0.0086154,0.0085548,0.0084947,0.008435,0.0083757,0.0083169,0.0082585,0.0082005, + 0.0081429,0.0080857,0.008029,0.0079726,0.0079167,0.0078611,0.007806,0.0077512,0.0076968, + 0.0076429,0.0075893,0.0075361,0.0074832,0.0074308,0.0073787,0.007327,0.0072756,0.0072247, + 0.007174,0.0071238,0.0070739,0.0070244,0.0069752,0.0069263,0.0068778,0.0068297,0.0067819, + 0.0067344,0.0066873,0.0066405,0.006594,0.0065479,0.0065021,0.0064566,0.0064114,0.0063666, + 0.0063221,0.0062779,0.006234,0.0061904,0.0061471,0.0061041,0.0060614,0.0060191,0.005977, + 0.0059352,0.0058938,0.0058526,0.0058117,0.0057711,0.0057307,0.0056907,0.005651,0.0056115, + 0.0055723,0.0055334,0.0054947,0.0054563,0.0054182,0.0053804,0.0053428] + #to extend this for other crystal materials here + else: raise Exception(strMatDataNotDefined) + + # Calculated parameters + dLat = srwl_uti_cryst_pl_sp(None, _mat) # lattice constant (A) + Vc = dLat*dLat*dLat # crystal cell volume + + #dr = dLat/norm(_hr) + dr = srwl_uti_cryst_pl_sp(_hr, _mat) + + wA = eV2wA/_en + #fE = interp(xE,ff1,ff2,En) + fE = interp_f1f2(xE, ff1, ff2, _en) + xh = 0.5/dr + #f0 = SiASF(0.) + f0 = srwl_uti_cryst_ASF(0., _mat) + + cF = wA*wA*re/(pi*Vc) + psi0r = -8.*cF*(f0+fE[0]) + psi0i = 8.*cF*fE[1] + #f0 = SiASF(xh) + f0 = srwl_uti_cryst_ASF(xh, _mat) + + #fDW = math.exp(-cDW*xh*xh) + fDW = exp(-cDW*xh*xh) + + cF = cF*fDW + eF = complex(0., 0.) + for x in rCell: + eF = eF + cmath.exp(2j*pi*(x[0]*_hr[0]+x[1]*_hr[1]+x[2]*_hr[2])) + aF = abs(eF) + + psiHr = -cF*aF*(f0+fE[0]) + psiHi = cF*aF*fE[1] + return [psi0r, psi0i, psiHr, psiHi] diff --git a/env/release/srw_python/srwl_uti_mag.py b/env/release/srw_python/srwl_uti_mag.py new file mode 100644 index 00000000..421c357c --- /dev/null +++ b/env/release/srw_python/srwl_uti_mag.py @@ -0,0 +1,285 @@ +############################################################################# +# SRWLib for Python: Magnet Utilities v 0.02 +############################################################################# + +from srwlib import * +#from copy import * + +#**************************************************************************** +def srwl_mag_kick(_el_en=3., _ang=1., _x_or_y='x', _len=1., _led=0): + """Setup dipole "kick" magnet + :param _el_en: electron energy [GeV] + :param _ang: kick angle [rad] + :param _x_or_y: plane (horizontal or vertical) + :param _len: effective magnet length [m] + :param _led: "soft" edge length for field variation from 10% to 90% [m]; G/(1 + ((z-zc)/d)^2)^2 fringe field dependence is assumed [m] + :param _zc: longitudinal position of the magnet center + :param _add: add (=1) or reset (=0) the new magnet structure to the existing approximate magnetic field container + """ + + if(_el_en <= 0): raise Exception('Electron Beam structure is not defined (it is required for defining kick magnet parameters from angle)') + if(_len <= 0): raise Exception('Inconsistent input magnet parameters: effective length can not be negative') + + if(_led > 0.): + d = 0.8078259211948791*_led #d parameter in G/(1 + ((z-zc)/d)^2)^2 + L0 = _len - 1.5707963267948966*d #length of const. magnetic field part + if(L0 < 0.): raise Exception('Inconsistent input magnet parameters: magnet edge length if too large for given effective length') + + B = -3.33564095*_ang*_el_en/_len #sign to be checked! + n_or_s = 'n' + if(_x_or_y == 'y'): n_or_s = 's' #to check + + return SRWLMagFldM(_G=B, _m=1, _n_or_s=n_or_s, _Leff=_len, _Ledge=_led) + +#**************************************************************************** +def srwl_mag_extrap_grad_off_mid_plane(_mag_mid, _ry, _ny, _grad_mult=1): + """ + Extrapolates magnetic field off horizontal mid-plane based on field gradient in the mid-plane (e.g. for dipole with gradient or for a guad). + :param _mag_mid: input tabulated 3D magnetic field on 2D mesh vs x and z in the horizontal mid-plane in a container (object of SRWLMagFldC type) + :param _ry: vertical position range of the final 3D mesh [m] + :param _ny: number of points vs vertical position in the final 3D mesh + :param _grad_mult: a number the gradient has to be multiplied by + :returns: resulting exrapolated 3D magnetic field structure in a container (object of SRWLMagFldC type) + """ + + if((_mag_mid is None) or (_mag_mid.arMagFld is None) or (len(_mag_mid.arMagFld) != 1) or (_ry < 0.) or (_ny <= 1)): + raise Exception("Incorrect input parameters for magnetic field to be extrapolated") + + fld3d_mid = _mag_mid.arMagFld[0] + #arBx_mid = fld3d_mid.arBx + arBy_mid = fld3d_mid.arBy + arBz_mid = fld3d_mid.arBz + + xc = _mag_mid.arXc[0] + xStart = xc - 0.5*fld3d_mid.rx + nx = fld3d_mid.nx + xStep = fld3d_mid.rx/(nx - 1) + + yc = 0 + yStart = -0.5*_ry + ny = int(_ny) + yStep = _ry/(ny - 1) + + zc = _mag_mid.arZc[0] + zStart = zc - 0.5*fld3d_mid.rz + nz = fld3d_mid.nz + zStep = fld3d_mid.rz/(nz - 1) + + nTotRes = int(nx*ny*nz) + arBxRes = array('d', [0]*nTotRes) + arByRes = array('d', [0]*nTotRes) + arBzRes = None if(arBz_mid is None) else array('d', [0]*nTotRes) + + nx_mi_1 = nx - 1 + #print(nx, xStart, xStep, ny, yStart, yStep, nz, zStart, zStep) + + for iz in range(nz): + iz_nx = iz*nx + iz_nx_ny = iz*nx*ny + for ix in range(nx): + b1y = 0; b2y = 0; b0y = 0; dx = xStep + if(ix == 0): + b1y = arBy_mid[iz_nx] + b2y = arBy_mid[iz_nx + 1] + b0y = b1y + elif(ix == nx_mi_1): + b1y = arBy_mid[iz_nx + nx_mi_1 - 1] + b2y = arBy_mid[iz_nx + nx_mi_1] + b0y = b2y + else: + b1y = arBy_mid[iz_nx + ix - 1] + b0y = arBy_mid[iz_nx + ix] + b2y = arBy_mid[iz_nx + ix + 1] + dx = 2*xStep + + curGrad = _grad_mult*(b2y - b1y)/dx + y = yStart + for iy in range(ny): + ofst = iz_nx_ny + iy*nx + ix + arBxRes[ofst] = y*curGrad + arByRes[ofst] = b0y + y += yStep + + fld3dRes = SRWLMagFld3D(arBxRes, arByRes, arBzRes, nx, ny, nz, fld3d_mid.rx, _ry, fld3d_mid.rz) + #print(fld3dRes.nx, fld3dRes.rx, fld3dRes.ny, fld3dRes.ry, fld3dRes.nz, fld3dRes.rz) + + return SRWLMagFldC(fld3dRes, xc, yc, zc) + +#**************************************************************************** +def srwl_mag_track_e_beam_mom(_e_beam, _mag, _z_or_ct, _ct_start=0, _ct_end=0, _npart=1000, _np_in_trj=10000): + """Estimate Electron Beam Statistical Moments at a given long. pos. (for tests) + :param _e_beam: input electron beam structure (object of SRWLPartBeam type) + :param _mag: input magnetic field container (object of SRWLMagFldC type) + :param _z_or_ct: longitudinal position [m] where the stat. moments have to be calculated, or c*t (if _ct_start != _ct_end) + :param _ct_start: start time ct moment [m] for trajectory calculation + :param _ct_end: end timect moment [m] for trajectory calculation + :param _npart: number of macro-particles + :param _np_in_trj: number of points in trajectory + """ + + partTraj = SRWLPrtTrj() + partTraj.allocate(_np_in_trj, True) + partTraj.ctStart = _ct_start #Start Time for the calculation + partTraj.ctEnd = _ct_end #magFldCnt.arMagFld[0].rz + + x0 = _e_beam.partStatMom1.x + xp0 = _e_beam.partStatMom1.xp + y0 = _e_beam.partStatMom1.y + yp0 = _e_beam.partStatMom1.yp + #en0GeV = _e_beam.partStatMom1.get_E() + gamma0 = _e_beam.partStatMom1.gamma + + sigXe2 = _e_beam.arStatMom2[0] #[0]: <(x-x0)^2> + mXXp = _e_beam.arStatMom2[1] #[1]: <(x-x0)*(xp-xp0)> + sigXpe2 = _e_beam.arStatMom2[2] #[2]: <(xp-xp0)^2> + sigYe2 = _e_beam.arStatMom2[3] #[3]: <(y-y0)^2> + mYYp = _e_beam.arStatMom2[4] #[4]: <(y-y0)*(yp-yp0)> + sigYpe2 = _e_beam.arStatMom2[5] #[5]: <(yp-yp0)^2> + relEnSpr = sqrt(_e_beam.arStatMom2[10]) #<(E-E0)^2>/E0^2 + #absEnSpr = en0GeV*relEnSpr + + multX = 0.5/(sigXe2*sigXpe2 - mXXp*mXXp) + BX = sigXe2*multX + GX = sigXpe2*multX + AX = mXXp*multX + sigPX = 1/sqrt(2*GX) + sigQX = sqrt(sigXpe2) + + multY = 0.5/(sigYe2*sigYpe2 - mYYp*mYYp) + BY = sigYe2*multY + GY = sigYpe2*multY + AY = mYYp*multY + sigPY = 1/sqrt(2*GY) + sigQY = sqrt(sigYpe2) + + randAr = array('d', [0]*5) #for random Gaussian numbers + random.seed(12345) + + ind0 = 0 + r0 = 0 + ctStep = 0 + treatCT = False + np_in_trj_mi_1 = _np_in_trj - 1 + if(_ct_start != _ct_end): #treat _z_or_ct as ct + ctStep = (_ct_end - _ct_start)/np_in_trj_mi_1 + ind0 = int((_z_or_ct - _ct_start)/ctStep) + if((ind0 >= 0) and (ind0 < np_in_trj_mi_1)): + r0 = (_z_or_ct - (_ct_start + ind0*ctStep))/ctStep + treatCT = True + if(treatCT is not True): + raise Exception("Trajectory point corresponding to given time moment was not found") + + xSum = 0; ySum = 0 + xpSum = 0; ypSum = 0 + xe2Sum = 0; ye2Sum = 0 + xpe2Sum = 0; ype2Sum = 0 + xxpSum = 0; yypSum = 0 + for i in range(_npart): + + for ir in range(5): + randAr[ir] = random.gauss(0, 1) + + auxPXp = sigQX*randAr[0] + auxPX = sigPX*randAr[1] + AX*auxPXp/GX + partTraj.partInitCond.x = x0 + auxPX + partTraj.partInitCond.xp = xp0 + auxPXp + auxPYp = sigQY*randAr[2] + auxPY = sigPY*randAr[3] + AY*auxPYp/GY + partTraj.partInitCond.y = y0 + auxPY + partTraj.partInitCond.yp = yp0 + auxPYp + partTraj.partInitCond.gamma = gamma0*(1 + relEnSpr*randAr[4]) + + partTraj = srwl.CalcPartTraj(partTraj, _mag, [1]) + + if treatCT is False: + #Search for longitudinal position: + iz = ind0 + dZprev = 1.e+23 + newIndFound = False + while(iz >= 0): + if(iz < np_in_trj_mi_1): + if((partTraj.arZ[iz] <= _z_or_ct) and (_z_or_ct < partTraj.arZ[iz + 1])): + ind0 = iz + newIndFound = True + break + dZ = abs(_z_or_ct - partTraj.arZ[iz]) + if(dZ > dZprev): break + + dZprev = dZ + iz -= 1 + + if newIndFound is False: + iz = ind0 + dZprev = 1.e+23 + while(iz < np_in_trj_mi_1): + if((partTraj.arZ[iz] <= _z_or_ct) and (_z_or_ct < partTraj.arZ[iz + 1])): + ind0 = iz + newIndFound = True + break + dZ = abs(_z_or_ct - partTraj.arZ[iz]) + if(dZ > dZprev): break + + dZprev = dZ + iz += 1 + + if(newIndFound is False): + raise Exception("Trajectory point corresponding to given longitudinal position was not found") + + r0 = (_z_or_ct - partTraj.arZ[ind0])/(partTraj.arZ[ind0 + 1] - partTraj.arZ[ind0]) + + x1 = partTraj.arX[ind0]; x2 = partTraj.arX[ind0 + 1] + x = x1 + r0*(x2 - x1) + xp1 = partTraj.arXp[ind0]; xp2 = partTraj.arXp[ind0 + 1] + xp = xp1 + r0*(xp2 - xp1) + y1 = partTraj.arY[ind0]; y2 = partTraj.arY[ind0 + 1] + y = y1 + r0*(y2 - y1) + yp1 = partTraj.arYp[ind0]; yp2 = partTraj.arYp[ind0 + 1] + yp = yp1 + r0*(yp2 - yp1) + + xSum += x; ySum += y + xpSum += xp; ypSum += yp + xe2Sum += x*x; ye2Sum += y*y + xpe2Sum += xp*xp; ype2Sum += yp*yp + xxpSum += x*xp; yypSum += y*yp + + invN = 1./_npart + xAvg = xSum*invN; yAvg = ySum*invN + xpAvg = xpSum*invN; ypAvg = ypSum*invN + xe2Avg = xe2Sum*invN; ye2Avg = ye2Sum*invN + xpe2Avg = xpe2Sum*invN; ype2Avg = ype2Sum*invN + xxpAvg = xxpSum*invN; yypAvg = yypSum*invN + + sigXe2 = xe2Avg - xAvg*xAvg; sigYe2 = ye2Avg - yAvg*yAvg + mXXp = xxpAvg - xAvg*xpAvg; mYYp = yypAvg - yAvg*ypAvg + sigXpe2 = xpe2Avg - xpAvg*xpAvg; sigYpe2 = ype2Avg - ypAvg*ypAvg + + return [[xAvg, xpAvg, sigXe2, mXXp, sigXpe2], [yAvg, ypAvg, sigYe2, mYYp, sigYpe2]] + +#**************************************************************************** +##def srwl_mag_extrap_grad_curv(_mag_curv_mid, _cen_trj_data, _xi, _xf, _nx, _yi, _yf, _ny, _zi, _zf, _nz, _grad_mult=1): +## """ +## Extrapolates magnetic field on rectangulat 3D mesh in and off horizontal mid-plane based on field gradient in the mid-plane (e.g. for dipole with gradient or for a guad). +## :param _mag_curv_mid: input tabulated 3D magnetic field on 2D mesh vs x and z in Natural frame in the horizontal mid-plane in a container (object of SRWLMagFldC type) +## :param _cen_trj_data: central trajectory data defining the Natural frame of the input magnetic field (_cen_trj_data[0] is ct, _cen_trj_data[1] is x. _cen_trj_data[2] is z) +## :param _xi: horizontal initial position of the final 3D mesh [m] +## :param _xf: horizontal final position of the final 3D mesh [m] +## :param _nx: number of points vs horizontal position in the final 3D mesh +## :param _yi: vertical initial position of the final 3D mesh [m] +## :param _yf: vertical initial position of the final 3D mesh [m] +## :param _ny: number of points vs vertical position in the final 3D mesh +## :param _zi: longitudinal initial position of the final 3D mesh [m] +## :param _zf: longitudinal final position of the final 3D mesh [m] +## :param _nz: number of points vs longitudinal position in the final 3D mesh +## :param _grad_mult: a number the gradient has to be multiplied by +## :returns: exrapolated 3D magnetic field structure in a container (object of SRWLMagFldC type) +## """ +## +## if((_mag_curv_mid is None) or (_mag_curv_mid.arMagFld is None) or (len(_mag_curv_mid.arMagFld) < 1) or (_cen_trj_data is None) or (len(_cen_trj_data) < 3) +## or (_nx < 1) or (_ny < 1) or (_nz < 1)): +## raise Exception("Incorrect input parameters for magnetic field to be extrapolated") +## #print('In srwl_fld_extrap_grad_curv') +## +## fld3d_curv_mid = _mag_curv_mid.arMagFld[0] +## #arBx_curv_mid = fld3d_curv_mid.arBx +## arBy_curv_mid = fld3d_curv_mid.arBy +## arBz_curv_mid = fld3d_curv_mid.arBz diff --git a/env/release/srw_python/srwl_uti_smp.py b/env/release/srw_python/srwl_uti_smp.py new file mode 100644 index 00000000..26671f7e --- /dev/null +++ b/env/release/srw_python/srwl_uti_smp.py @@ -0,0 +1,321 @@ +# -*- coding: utf-8 -*- +############################################################################# +# SRW Samples library +# Authors/Contributors: Maksim Rakitin +# October 26, 2016 +# October 27, 2017 +############################################################################# + +import math +import os + +import srwlib +import uti_io + + +# ********************** The class for Samples: +class SRWLUtiSmp: + """The class for Samples from image file (e.g., .tif), NumPy array (.npy), etc. + + :param file_path: full path to the image or the saved NumPy array. + :param area: the coordinates of the rectangle area listed in the following order: x_start, x_end, y_start, y_end. + :param rotate_angle: the angle [deg] to rotate the read image counterclockwise. See scipy.ndimage.interpolation.rotate() for details. + :param rotate_reshape: if reshape is true, the output shape is adapted so that the input array is contained completely in the output. + :param cutoff_background_noise: the ratio for cutoff the background noise (between 0 and 1). + :param background_color: the background color code to use instead of the background noise (0=black, 255=white). + :param tile: the list/tuple (rows, columns) to tile the cut area of the image. See numpy.tile() for details. + :param shift_x: shift the whole image horizontally. Positive value shifts the image to the right, negative - to the left. See numpy.pad() for details. + :param shift_y: shift the whole image vertically. Positive value shifts the image to the top, negative - to the bottom. See numpy.pad() for details. + :param invert: invert the image. See numpy.invert() for details. + :param is_show_images: a flag to show the initial and processed images. + :param is_save_images: a flag to save the initial and processed images. + :param raw_image_name: the name of the raw file in case if it's saved. + :param processed_image_name: the name of the processed file in case if it's saved. + :param prefix: the prefix to add to the names of the saved image files. + :param output_image_format: the format of the output file. If not specified, the input format is used. + """ + + def __init__(self, file_path, + area=None, rotate_angle=0, rotate_reshape=True, cutoff_background_noise=0.25, background_color=0, + tile=None, shift_x=None, shift_y=None, invert=None, + is_show_images=False, is_save_images=False, + raw_image_name='raw', processed_image_name='processed', prefix='', output_image_format=None): + # Input parameters: + self.file_path = file_path + self.area = area + self.rotate_angle = rotate_angle if rotate_angle is not None else 0 + self.rotate_reshape = True if rotate_reshape else False + self.cutoff_background_noise = cutoff_background_noise if cutoff_background_noise is not None else 0 + self.background_color = background_color if background_color is not None else 0 + self.invert = invert + self.tile = tile + self.shift_x = shift_x + self.shift_y = shift_y + self.is_show_images = is_show_images + self.is_save_images = is_save_images + output_image_format = os.path.splitext(file_path)[1].replace('.', '') if not output_image_format else \ + output_image_format + self.raw_image_name = self._add_prefix(prefix, raw_image_name, output_image_format) + self.processed_image_name = self._add_prefix(prefix, processed_image_name, output_image_format) + + # Output parameters: + self.data = None + self.raw_image = None + self.processed_image = None + self.nx = None + self.ny = None + self.limit_value = None + + # Check input type automatically: + self.input_type = self._check_input_type(file_path) + + # Set the dir where to save the files: + self.save_dir = os.path.abspath(os.path.dirname(file_path)) + + # Check the input file(s): + self._check_files() + + # Process input: + self.read_sample() + + # Show the resulted images: + if self.is_show_images: + self.show_images() + + # Save the resulted images: + if self.is_save_images: + self.save_images() + + def get_data_from_image(self): + import_err_msg = '"{}" library cannot be imported. Please install it first with "pip install {}".' + try: + import numpy as np + except ImportError: + raise ImportError(import_err_msg.format('NumPy', 'numpy')) + try: + from PIL import Image + except ImportError: + raise ImportError(import_err_msg.format('PIL', 'pillow')) + try: + from scipy.ndimage.interpolation import rotate + except ImportError: + raise ImportError(import_err_msg.format('SciPy', 'scipy')) + + d = uti_io.read_image(image_path=self.file_path) + self.data = d['data'] + self.raw_image = d['raw_image'] + self.limit_value = d['limit_value'] + + # Remove background noise: + assert 0 <= self.background_color <= 255, 'Background color ({}) should be between 0 and 255'.format( + self.background_color) + assert 0 <= self.cutoff_background_noise <= 1, 'Cutoff background noise ({}) should be between 0 and 1'.format( + self.cutoff_background_noise) + self.data[np.where(self.data < self.limit_value * self.cutoff_background_noise)] = np.uint16( + self.background_color) + + if self.area: + assert type(self.area) in [tuple, list] and len(self.area) == 4, \ + 'The area should be a list/tuple and contain 4 elements (x_start, x_end, y_start, y_end)' + assert self.area[0] <= self.data.shape[1] and self.area[1] <= self.data.shape[1] and \ + self.area[2] <= self.data.shape[0] and self.area[3] <= self.data.shape[0], \ + '\n x_start ({}) and x_end ({}) should be less than {}\n y_start ({}) and y_end ({}) should be less than {}'.format( + self.area[0], self.area[1], self.data.shape[1], + self.area[2], self.area[3], self.data.shape[0], + ) + assert self.area[0] < self.area[1] and \ + self.area[2] < self.area[3], \ + '\n x_start ({}) should be less than x_end ({})\n y_start ({}) should be less than y_end ({})'.format( + self.area[0], self.area[1], + self.area[2], self.area[3], + ) + self.data = self.data[self.area[2]:self.area[3], self.area[0]:self.area[1]] + + if self.tile: + assert type(self.tile) in [list, tuple], 'The type of tile ({}) should be list/tuple'.format( + type(self.tile).__name__) + assert len(self.tile) == 2, 'The size ({}) of the list/tuple should be 2'.format(len(self.tile)) + self.data = np.tile(self.data, self.tile) + + if self.rotate_angle: + assert -360 < self.rotate_angle < 360, 'The angle should be from -360 to 360 degrees.' + self.data = rotate(self.data, self.rotate_angle, axes=(1, 0), reshape=self.rotate_reshape, output=None, + order=0, mode='constant', cval=self.background_color, prefilter=False) + + if self.shift_x: + assert type(self.shift_x) is int, 'Type of shift_x ({}) should be int'.format(type(self.shift_x).__name__) + if self.shift_x > 0: + self.data = np.pad(self.data, ((0, 0), (self.shift_x, 0)), mode='constant', + constant_values=(self.background_color))[:, :-self.shift_x] + else: + self.data = np.pad(self.data, ((0, 0), (0, -self.shift_x)), mode='constant', + constant_values=(self.background_color))[:, -self.shift_x:] + + if self.shift_y: + assert type(self.shift_y) is int, 'Type of shift_y ({}) should be int'.format(type(self.shift_y).__name__) + if self.shift_y < 0: + self.data = np.pad(self.data, ((-self.shift_y, 0), (0, 0)), mode='constant', + constant_values=(self.background_color))[:self.shift_y, :] + else: + self.data = np.pad(self.data, ((0, self.shift_y), (0, 0)), mode='constant', + constant_values=(self.background_color))[self.shift_y:, :] + + if self.invert: + self.data = np.invert(self.data) + + self.processed_image = Image.fromarray(self.data) + + def get_image_from_data(self): + data = np.load(self.file_path) + self.limit_value = 255 + self.data = (data - data.min()) / (data.max() - data.min()) * self.limit_value + self.raw_image = Image.fromarray(self.data.astype(np.uint8)) + self.processed_image = self.raw_image + + def read_sample(self): + if self.input_type == 'image': + self.get_data_from_image() + elif self.input_type == 'npy': + self.get_image_from_data() + else: + raise NotImplementedError( + 'Processing of the "{}" input type is not implemented yet.'.format(self.input_type)) + self.nx = self.data.shape[1] + self.ny = self.data.shape[0] + + def save_images(self): + # self.raw_image.save(os.path.join(self.save_dir, self.raw_image_name)) + self.processed_image.save(os.path.join(self.save_dir, self.processed_image_name)) + + def show_images(self): + self.raw_image.show() + self.processed_image.show() + + def _add_prefix(self, prefix, name, image_format): + output_name = '{}_{}'.format(prefix, name) if prefix else name + return '{}.{}'.format(output_name, image_format) + + def _check_files(self): + if not os.path.isfile(self.file_path): + raise ValueError('Provided file "{}" does not exist.'.format(self.file_path)) + + def _check_input_type(self, file_path): + self.possible_extensions = { + 'image': ['tif', 'tiff', 'png', 'bmp', 'gif', 'jpg', 'jpeg'], + 'npy': ['npy'], + } + extension = os.path.splitext(file_path)[1][1:].lower() + for k in self.possible_extensions.keys(): + for e in self.possible_extensions[k]: + if extension == e: + return k + all_extensions = [x for x_list in self.possible_extensions.values() for x in x_list] + all_extensions += [x.upper() for x in all_extensions] + raise ValueError('Incorrect extension: {}. Possible values: {}.'.format(extension, ', '.join(all_extensions))) + + +# ********************** Create transmission element from the data from an image file: +def srwl_opt_setup_transm_from_file( + file_path, resolution, thickness, delta, atten_len, + arTr=None, extTr=0, fx=1e+23, fy=1e+23, + xc=0, yc=0, ne=1, e_start=0, e_fin=0, + area=None, rotate_angle=None, rotate_reshape=None, cutoff_background_noise=None, + background_color=None, tile=None, shift_x=None, shift_y=None, invert=None, + is_save_images=True, prefix='', output_image_format=None, +): + """Setup Sample element. + + :param file_path: path to the input file (image or .npy). + :param resolution: resolution of the image [m/pixel]. + :param thickness: thickness of the sample [m]. + :param delta: refractive index decrement. + :param atten_len: attenuation length [m]. + :param arTr: complex C-aligned data array (of 2*ne*nx*ny length) storing amplitude transmission and optical path difference as function of transverse coordinates. + :param extTr: transmission outside the grid/mesh is zero (0), or it is same as on boundary (1). + :param fx: estimated focal length in the horizontal plane [m]. + :param fy: estimated focal length in the vertical plane [m]. + :param xc: horizontal coordinate of center [m]. + :param yc: vertical coordinate of center [m]. + :param ne: number of transmission data points vs photon energy. + :param e_start: initial photon energy [eV]. + :param e_fin: final photon energy [eV]. + :param area: the coordinates of the rectangle area listed in the following order: x_start, x_end, y_start, y_end. + :param rotate_angle: the angle [deg] to rotate the read image counterclockwise. See scipy.ndimage.interpolation.rotate() for details. + :param rotate_reshape: if reshape is true, the output shape is adapted so that the input array is contained completely in the output. + :param cutoff_background_noise: the ratio for cutoff the background noise (between 0 and 1). + :param background_color: the background color code to use instead of the background noise (0=black, 255=white). + :param tile: the list/tuple (rows, columns) to tile the cut area of the image. See numpy.tile() for details. + :param shift_x: shift the whole image horizontally. Positive value shifts the image to the right, negative - to the left. See numpy.pad() for details. + :param shift_y: shift the whole image vertically. Positive value shifts the image to the top, negative - to the bottom. See numpy.pad() for details. + :param invert: invert the image. See numpy.invert() for details. + :param is_save_images: a flag to save the initial and processed images. + :param prefix: the prefix to add to the names of the saved image files. + :param output_image_format: the format of the output file. If not specified, the input format is used. + :return: transmission (SRWLOptT) type optical element which simulates the Sample. + """ + + input_parms = { + "type": "sample", + "resolution": resolution, + "thickness": thickness, + "refractiveIndex": delta, + "attenuationLength": atten_len, + "horizontalCenterCoordinate": xc, + "verticalCenterCoordinate": yc, + "initialPhotonEnergy": e_start, + "finalPhotonPnergy": e_fin, + 'area': area, + 'rotateAngle': rotate_angle, + 'rotateReshape': rotate_reshape, + 'cutoffBackgroundNoise': cutoff_background_noise, + 'backgroundColor': background_color, + 'tile': tile, + 'shiftX': shift_x, + 'shiftY': shift_y, + 'invert': invert, + 'outputImageFormat': output_image_format, + } + + s = SRWLUtiSmp( + file_path=file_path, + area=area, + rotate_angle=rotate_angle, + rotate_reshape=rotate_reshape, + cutoff_background_noise=cutoff_background_noise, + background_color=background_color, + tile=tile, + shift_x=shift_x, + shift_y=shift_y, + invert=invert, + is_show_images=False, + is_save_images=is_save_images, + prefix=prefix, + output_image_format=output_image_format, + ) + + # Input parameters to SRWLOptT: + nx = s.nx + ny = s.ny + rx = nx * resolution + ry = ny * resolution + + opT = srwlib.SRWLOptT(_nx=nx, _ny=ny, _rx=rx, _ry=ry, + _arTr=arTr, _extTr=extTr, _Fx=fx, _Fy=fy, + _x=xc, _y=yc, _ne=ne, _eStart=e_start, _eFin=e_fin) + + data = s.data + + # Same data alignment as for wavefront: outmost loop vs y, inmost loop vs e + offset = 0 + for iy in range(ny): + for ix in range(nx): + for ie in range(ne): + # In images Y=0 corresponds from upper-left corner, in SRW it's lower-left corner: + pathInBody = thickness * data[ny - iy - 1, ix] / s.limit_value + opT.arTr[offset] = math.exp(-0.5 * pathInBody / atten_len) # amplitude transmission + opT.arTr[offset + 1] = -delta * pathInBody # optical path difference + offset += 2 + + opT.input_parms = input_parms + + return opT diff --git a/env/release/srw_python/srwl_uti_src.py b/env/release/srw_python/srwl_uti_src.py new file mode 100644 index 00000000..c73ad8f9 --- /dev/null +++ b/env/release/srw_python/srwl_uti_src.py @@ -0,0 +1,116 @@ +############################################################################# +# SRWLib for Python Utility module for Synchrotron Sources (electron beams and ID parameters) +# Author: O.C. +# v 0.02 +############################################################################# + +from srwlib import * + +#**************************************************************************** +#def srwl_uti_src_e_beams_predef(): +def srwl_uti_src_e_beam_predef(): #OC25012017 + #E-Beam params in the order: _Iavg, _e, _sig_e, _emit_x, _beta_x, _alpha_x, _eta_x, _eta_x_pr, _emit_y, _beta_y, _alpha_y + allBeams = [ + #['NSLS-II Low Beta Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 2.02, 0, 0, 0, 8e-12, 1.06, 0]], + #['NSLS-II Low Beta Final', [0.5, 3, 0.89e-03, 0.55e-09, 2.02, 0, 0, 0, 8e-12, 1.06, 0]], + ['NSLS-II Low Beta Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 1.84, 0, 0, 0, 8e-12, 1.17, 0]], + ['NSLS-II Low Beta Final', [0.5, 3, 0.89e-03, 0.55e-09, 1.84, 0, 0, 0, 8e-12, 1.17, 0]], + #['NSLS-II High Beta Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 20.85, 0, 0, 0, 8e-12, 3.4, 0]], + #['NSLS-II High Beta Final', [0.5, 3, 0.89e-03, 0.55e-09, 20.85, 0, 0, 0, 8e-12, 3.4, 0]], + ['NSLS-II High Beta Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 20.1, 0, 0, 0, 8e-12, 3.4, 0]], + ['NSLS-II High Beta Final', [0.5, 3, 0.89e-03, 0.55e-09, 20.1, 0, 0, 0, 8e-12, 3.4, 0]], + ['NSLS-II 3PW Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 2.956, 1.932, 0.137, -0.105, 8e-12, 19.653, -0.806]], + ['NSLS-II 3PW Final', [0.5, 3, 0.89e-03, 0.55e-09, 2.956, 1.932, 0.137, -0.105, 8e-12, 19.653, -0.806]], + ['NSLS-II BM Day 1', [0.5, 3, 0.89e-03, 0.9e-09, 1.5, 0, 0.137, -0.1, 8e-12, 22.5, -0.9]], + ['NSLS-II BM Final', [0.5, 3, 0.89e-03, 0.55e-09, 1.5, 0, 0.137, -0.1, 8e-12, 22.5, -0.9]], + ['DIAMOND Low Beta', [0.3, 3, 1.0e-03, 2.797e-09, 2.283, 0, 0, 0, 24.32e-12, 2.514, 0]], + ['SOLEIL Short', [0.5, 2.75, 1.016e-03, 3.73e-09, 17.78, 0, 0.28, 0, 37e-12, 1.75, 0]], + ['SOLEIL Medium', [0.5, 2.75, 1.016e-03, 3.73e-09, 4.0, 0, 0.13, 0, 37e-12, 1.77, 0]], + ['SOLEIL Long', [0.5, 2.75, 1.016e-03, 3.73e-09, 10.09, 0, 0.2, 0, 37e-12, 8.01, 0]], + ['SOLEIL BM 1 deg.', [0.5, 2.75, 1.016e-03, 3.73e-09, 0.603, 0.776, 0.039, -0.088, 37e-12, 16.53, 0.931]], + ['SOLEIL BM 4 deg.', [0.5, 2.75, 1.016e-03, 3.73e-09, 0.375, 0.024, 0.021, -0.037, 37e-12, 16.01, 0.899]], + ['ESRF Low Beta', [0.2, 6.04, 1.1e-03, 4.e-09, 0.35, 0, 0.031, 0, 25e-12, 2.97, 0]], + ['ESRF High Beta', [0.2, 6.04, 1.1e-03, 4.e-09, 37.6, 0, 0.134, 0, 25e-12, 2.95, 0]], + ['ESRF BM', [0.2, 6.04, 1.1e-03, 4.e-09, 2.2, 1.43, 0.045, 0, 25e-12, 34.9, 0]], #to correct _alpha_x, _alpha_y, _eta_x_pr + ['ESRF-U BM', [0.2, 6., 0.95e-03, 0.13e-09, 1.8138, -2.02, 0.018, 0.016, 5e-12, 2.5685, 1.9307]], + ['APS', [0.1, 7, 0.96e-03, 2.79e-09, 22.7, 0, 0.206, 0, 8.4e-12, 3.1, 0]], + ['SPring8 High Beta', [0.1, 8, 1.1e-03, 3.4e-09, 22.6, 0, 0.107, 0, 6.8e-12, 5.6, 0]] + ]#add more beams + return allBeams + +#**************************************************************************** +def srwl_uti_src_e_beam(_nm, _Iavg=None, _e=None, _sig_e=None, _emit_x=None, _beta_x=None, _alpha_x=None, _eta_x=None, _eta_x_pr=None, _emit_y=None, _beta_y=None, _alpha_y=None): +#def srwl_uti_src_e_beam(_nm): + """Instantiates electron beam structures describing different existing sources + :param _name: string identifying a source + :return: SRWLPartBeam object + """ + #allBeams = srwl_uti_src_e_beams_predef() + allBeams = srwl_uti_src_e_beam_predef() #OC25012017 + sTest = _nm.replace(' ', '') + sTest = sTest.replace('-', '') + sTest = sTest.capitalize() + + resBeam = SRWLPartBeam() + nBeams = len(allBeams) + for i in range(nBeams): + curInf = allBeams[i] + curStr = curInf[0] + curStr = curStr.replace(' ', '') + curStr = curStr.replace('-', '') + curStr = curStr.capitalize() + if sTest == curStr: + ar = curInf[1] + if(_Iavg is not None): ar[0] = _Iavg + if(_e is not None): ar[1] = _e + if(_sig_e is not None): ar[2] = _sig_e + if(_emit_x is not None): ar[3] = _emit_x + if(_beta_x is not None): ar[4] = _beta_x + if(_alpha_x is not None): ar[5] = _alpha_x + if(_eta_x is not None): ar[6] = _eta_x + if(_eta_x_pr is not None): ar[7] = _eta_x_pr + if(_emit_y is not None): ar[8] = _emit_y + if(_beta_y is not None): ar[9] = _beta_y + if(_alpha_y is not None): ar[10] = _alpha_y + resBeam.from_Twiss(_Iavg=ar[0], _e=ar[1], _sig_e=ar[2], _emit_x=ar[3], _beta_x=ar[4], _alpha_x=ar[5], _eta_x=ar[6], _eta_x_pr=ar[7], _emit_y=ar[8], _beta_y=ar[9], _alpha_y=ar[10]) + return resBeam + return None + +#**************************************************************************** +def srwl_uti_src_sph_wave(_wfr, _pol, _norm=1): #Move it to different place (C part?) + """Auxiliary function: sets up spherical wavefront of a point source + :param _wfr: wavefront structure to be set up, using its input params + :param _pol: electric field polarization to set: =0 -Linear Horizontal; =1 -Linear Vertical; + :param _norm: normalizing coeficient + """ + + R = _wfr.mesh.zStart #0.5*(_wfr.Rx + _wfr.Ry) + Re2 = R*R + arE = _wfr.arEx if(_pol == 0) else _wfr.arEy + + multE = _norm #to update, assuming _norm defining power of the source + + eStep = 0 if(_wfr.mesh.ne <= 1) else (_wfr.mesh.eFin - _wfr.mesh.eStart)/(_wfr.mesh.ne - 1) + xStep = (_wfr.mesh.xFin - _wfr.mesh.xStart)/(_wfr.mesh.nx - 1) + yStep = (_wfr.mesh.yFin - _wfr.mesh.yStart)/(_wfr.mesh.ny - 1) + + i = 0 + y = _wfr.mesh.yStart - yStep - _wfr.yc + for iy in range(_wfr.mesh.ny): + y += yStep + ye2 = y*y + x = _wfr.mesh.xStart - xStep - _wfr.xc + for ix in range(_wfr.mesh.nx): + x += xStep + xe2 = x*x + curR = sqrt(Re2 + xe2 + ye2) + mult = multE/curR + phEn = _wfr.mesh.eFin - eStep + for ie in range(_wfr.mesh.ne): + phEn += eStep + k = (5.067730652e+06)*phEn + ph = k*curR + arE[i] = mult*cos(ph) + arE[i + 1] = mult*sin(ph) + i += 2 + diff --git a/env/release/srw_python/srwl_uti_und.py b/env/release/srw_python/srwl_uti_und.py new file mode 100644 index 00000000..fe94c591 --- /dev/null +++ b/env/release/srw_python/srwl_uti_und.py @@ -0,0 +1,1126 @@ +############################################################################# +# SRWLib for Python: Undulator Utilities v 0.02 +############################################################################# + +from srwlib import * +import uti_parse +import uti_io + +#**************************************************************************** +def srwl_und_cor_fld_int(_mag3d, _dist_bw_kicks, _rms_len_kicks=0.05, _zc=0, _zcMesh=0, _zRange=0, _dupl=False): + """ + Compensates 1st and 2nd integrals of undulator field by adding "kicks" before and after the undulator. + :param _mag3d: 3D magnetic field of undulator (object of SRWLMagFld3D type) + :param _dist_bw_kicks: distance between kicks (in longitudinal direction) [m] + :param _rms_len_kicks: RMS kick length [m] + :param _zc: center position for the kick set (~center of indulator) [m] + :param _zcMesh: longitudinal center position for the magnetic field mesh [m] + :param _zRange: range of magnetic field to be taken into account [m] + :param _dupl: duplicate the magnetic field object or not + :returns: undated magnetic 3d field structure + """ + + if(_mag3d.nz <= 1): return _mag3d + + nz = _mag3d.nz + zStep = _mag3d.rz/(nz - 1) + + #print(0.5*_dist_bw_kicks, _rms_len_kicks, _zc) + + halfDistBwKicks = 0.5*_dist_bw_kicks + zIn = _zc - halfDistBwKicks #Position of Input Kick + zOut = _zc + halfDistBwKicks #Position of Output Kick + + #zE = 0.5*_mag3d.rz #? End position of magnetic field + #zB = -zE #? Start position of magnetic field + halfFullRangeZ = 0.5*_mag3d.rz + zB = _zcMesh - halfFullRangeZ #? End position of magnetic field + zE = _zcMesh + halfFullRangeZ #? Start position of magnetic field + + #print('zIn=', zIn, 'zOut=', zOut, 'zc=', _zc) + #print('zB=', zB, 'zE=', zE) + + zBr = zB + zEr = zE + if(_zRange > 0.): + halfRange = 0.5*_zRange + zBr = _zcMesh - halfRange + zEr = _zcMesh + halfRange + + invDistBwKicks = 1./_dist_bw_kicks + + arBxOrig = _mag3d.arBx + arByOrig = _mag3d.arBy + manyTrPos = False + if((_mag3d.nx > 1) or (_mag3d.ny > 1)): + manyTrPos = True + arBxOrig = array('d', [0]*nz) + arByOrig = array('d', [0]*nz) + + halfRangeZ = 4.*_rms_len_kicks + izInB = round((zIn - halfRangeZ - zB)/zStep) + if(izInB < 0): izInB = 0 + izInE = round((zIn + halfRangeZ - zB)/zStep) + if(izInE >= nz): izInE = nz - 1 + izOutB = round((zOut - halfRangeZ - zB)/zStep) + if(izOutB < 0): izOutB = 0 + izOutE = round((zOut + halfRangeZ - zB)/zStep) + if(izOutE >= nz): izOutE = nz - 1 + + izBr = round((zBr - zB)/zStep) + if(izBr < 0): izBr = 0 + izEr = round((zEr - zB)/zStep) + if(izEr >= nz): izEr = nz - 1 + + resMag3d = _mag3d + if(_dupl == True): resMag3d = deepcopy(_mag3d) + arBxRes = resMag3d.arBx + arByRes = resMag3d.arBy + + #print(izInB, izInE, izOutB, izOutE) + #print(izInB, izInE, izOutB, izOutE) + #print(izBr, izEr) + + perY = _mag3d.nx + perZ = perY*_mag3d.ny + for iy in range(_mag3d.ny): + iy_perY = iy*perY + for ix in range(_mag3d.nx): + if(manyTrPos == True): + arBxTot = _mag3d.arBx + arByTot = _mag3d.arBy + for iz in range(nz): + ofst = ix + iy_perY + iz*perZ + if(arBxTot is not None): + arBxOrig = arBxTot[ofst] + if(arByTot is not None): + arByOrig = arByTot[ofst] + + if(arBxOrig is not None): + arBxInt = uti_math.integ_array(arBxOrig, zStep, True) + + #auxI1X = -arBxInt[nz - 1] #[T.m] + auxI1X_Er = arBxInt[izEr] + auxI1X_Br = arBxInt[izBr] + auxI1X = -(auxI1X_Er - auxI1X_Br) #[T.m] + + arBxInt = uti_math.integ_array(arBxInt, zStep, True) + #auxI2X = -arBxInt[nz - 1] #[T.m^2] + auxI2X = -(arBxInt[izEr] - arBxInt[izBr] - auxI1X_Br*(izEr - izBr)*zStep) #[T.m^2] + + kickI1Xin = (auxI2X - auxI1X*(zE - zOut))*invDistBwKicks + kickI1Xout = (auxI1X - kickI1Xin) + + #print(auxI1X, 'T.m') + #print(kickI1Xin*(zE - zIn), kickI1Xout*(zE - zOut)) + #I2test = kickI1Xin*(zE - zIn) + kickI1Xout*(zE - zOut) + #print(auxI2X, I2test) + + B0kickX = kickI1Xin*0.3989422804/_rms_len_kicks + z = zB + zStep*izInB + for iz in range(izInB, izInE + 1): + ofst = ix + iy_perY + iz*perZ + t = (z - zIn)/_rms_len_kicks + arBxRes[ofst] += B0kickX*exp(-0.5*t*t) + z += zStep + B0kickX = kickI1Xout*0.3989422804/_rms_len_kicks + z = zB + zStep*izOutB + for iz in range(izOutB, izOutE + 1): + ofst = ix + iy_perY + iz*perZ + t = (z - zOut)/_rms_len_kicks + arBxRes[ofst] += B0kickX*exp(-0.5*t*t) + z += zStep + + if(arByOrig is not None): + arByInt = uti_math.integ_array(arByOrig, zStep, True) + + #auxI1Y = -arByInt[nz - 1] #[T.m] + auxI1Y_Er = arByInt[izEr] + auxI1Y_Br = arByInt[izBr] + auxI1Y = -(auxI1Y_Er - auxI1Y_Br) #[T.m] + + arByInt = uti_math.integ_array(arByInt, zStep, True) + #auxI2Y = -arByInt[nz - 1] #[T.m^2] + auxI2Y = -(arByInt[izEr] - arByInt[izBr] - auxI1Y_Br*(izEr - izBr)*zStep) #[T.m^2] + + kickI1Yin = (auxI2Y - auxI1Y*(zE - zOut))*invDistBwKicks + kickI1Yout = (auxI1Y - kickI1Yin) + + #print(auxI1Y, 'T.m') + #I2test = kickI1Yin*(zE - zIn) + kickI1Yout*(zE - zOut) + #print(auxI2Y, I2test) + + B0kickY = kickI1Yin*0.3989422804/_rms_len_kicks + z = zB + zStep*izInB + for iz in range(izInB, izInE + 1): + ofst = ix + iy_perY + iz*perZ + t = (z - zIn)/_rms_len_kicks + arByRes[ofst] += B0kickY*exp(-0.5*t*t) + z += zStep + B0kickY = kickI1Yout*0.3989422804/_rms_len_kicks + z = zB + zStep*izOutB + for iz in range(izOutB, izOutE + 1): + ofst = ix + iy_perY + iz*perZ + t = (z - zOut)/_rms_len_kicks + arByRes[ofst] += B0kickY*exp(-0.5*t*t) + z += zStep + return resMag3d + +#**************************************************************************** +def srwl_und_fld_add_const(_mag3d, _zcMesh=0, _zc=0, _zRange=0, _bx=0, _by=0, _bz=0, _dupl=False): + """ + Adds constant magnetic field within given longitudinal range. + :param _mag3d: 3D magnetic field of undulator (object of SRWLMagFld3D type) + :param _zcMesh: longitudinal center position for the magnetic field mesh [m] + :param _zc: center position for the dipole field range [m] + :param _zRange: range of magnetic field over which to add constant field [m] + :param _bx: horizontal field component to add [T] + :param _by: vertical field component to add [T] + :param _bz: longitudinal field component to add [T] + :param _dupl: duplicate the magnetic field object or not + :returns: undated magnetic 3d field structure + """ + + if(_mag3d.nz <= 1): return _mag3d + + nz = _mag3d.nz + zStep = _mag3d.rz/(nz - 1) + inv_zStep = 0. if(zStep == 0.) else 1./zStep + + izAddB = 0 + izAddE = nz - 1 + + if(_zRange > 0): + halfFullRangeZ = 0.5*_mag3d.rz + zB = _zcMesh - halfFullRangeZ #? End position of magnetic field + zE = _zcMesh + halfFullRangeZ #? Start position of magnetic field + + halfRange = 0.5*_zRange + zAddB = _zc - halfRange + zAddE = _zc + halfRange + + izAddTestB = int(round((zAddB - zB)*inv_zStep)) + izAddTestE = int(round((zAddE - zB)*inv_zStep)) + + if(izAddTestB <= izAddTestE): + if((izAddB < izAddTestB) and (izAddTestB <= izAddE)): izAddB = izAddTestB + if((izAddB <= izAddTestE) and (izAddTestE < izAddE)): izAddE = izAddTestE + + resMag3d = _mag3d + if(_dupl == True): resMag3d = deepcopy(_mag3d) + + arBX = resMag3d.arBx + arBY = resMag3d.arBy + arBZ = resMag3d.arBz + + bxIsSet = False + if(arBX is not None): + if(len(arBX) > 0): bxIsSet = True + byIsSet = False + if(arBY is not None): + if(len(arBY) > 0): byIsSet = True + bzIsSet = False + if(arBZ is not None): + if(len(arBZ) > 0): bzIsSet = True + + for iz in range(izAddB, izAddE + 1): + if(bxIsSet == True): arBX[iz] += _bx + if(byIsSet == True): arBY[iz] += _by + if(bzIsSet == True): arBZ[iz] += _bz + + return resMag3d + +#**************************************************************************** +def srwl_und_cut_fld(_mag3d, _res_rz, _zc=None, _dupl=False): + """ + Cuts (truncates) undulator magnetic field. Assumes equidistant mesh. + :param _mag3d: 3D magnetic field of undulator (object of SRWLMagFld3D type) + :param _res_rz: range vs longitudinal position to produce [m] + :param _zc: center position for the kick set (~center of indulator) [m] + :param _dupl: duplicate the magnetic field object or not + :returns: updated 3d magnetic field structure + """ + + if(_mag3d.nz <= 1): return _mag3d + + nx = _mag3d.nx + ny = _mag3d.ny + nz = _mag3d.nz + zStep = _mag3d.rz/(nz - 1) + #zRange = zStep*(nz - 1) + zRange = _mag3d.rz + + if((_res_rz <= 0) or (_res_rz >= zRange)): + if(_dupl == False): return _mag3d + else: return deepcopy(_mag3d) + + zBegOrig = -0.5*zRange + zEndOrig = -zBegOrig + + perZ = nx*ny + + arBxOrig = _mag3d.arBx + arByOrig = _mag3d.arBy + arBzOrig = _mag3d.arBz + + if(_zc is None): + #Find Max. field value and position + Be2max = 0. + i = 0 + for iz in range(nz): + for iy in range(ny): + for ix in range(nx): + Bx = 0 if arBxOrig is None else arBxOrig[i] + By = 0 if arByOrig is None else arByOrig[i] + Bz = 0 if arBzOrig is None else arBzOrig[i] + curBe2 = Bx*Bx + By*By + Bz*Bz + if(Be2max < curBe2): Be2max = curBe2 + i += 1 + + #Find Longitudinal Center position of the field + Bthresh = sqrt(Be2max)*0.1 #to steer + #print('Bthresh=', Bthresh) + + i = 0; izStart = 0 + wasBreak = False + for iz in range(nz): + for iy in range(ny): + for ix in range(nx): + Bx = 0 if arBxOrig is None else arBxOrig[i] + By = 0 if arByOrig is None else arByOrig[i] + Bz = 0 if arBzOrig is None else arBzOrig[i] + curB = sqrt(Bx*Bx + By*By + Bz*Bz) + #print('i=', i, 'curB=', curB) + + if(curB >= Bthresh): + izStart = iz + wasBreak = True + break + i += 1 + if(wasBreak): break + if(wasBreak): break + + izEnd = nz - 1 + wasBreak = False + for iz in range(nz - 1, -1, -1): + iz_perZ = iz*perZ + for iy in range(ny): + iy_nx_p_iz_perZ = iy*nx + iz_perZ + for ix in range(nx): + i = ix + iy_nx_p_iz_perZ + Bx = 0 if arBxOrig is None else arBxOrig[i] + By = 0 if arByOrig is None else arByOrig[i] + Bz = 0 if arBzOrig is None else arBzOrig[i] + curB = sqrt(Bx*Bx + By*By + Bz*Bz) + if(curB >= Bthresh): + izEnd = iz + wasBreak = True + break + if(wasBreak): break + if(wasBreak): break + + #print('izStart=', izStart, 'izEnd=', izEnd) + + zStart = zBegOrig + izStart*zStep + zEnd = zBegOrig + izEnd*zStep + _zc = 0.5*(zStart + zEnd) + + halfResRangeZ = 0.5*_res_rz + zStartRes = _zc - halfResRangeZ + if(zStartRes < zBegOrig): zStartRes = zBegOrig + zEndRes = _zc + halfResRangeZ + if(zEndRes > zEndOrig): zEndRes = zEndOrig + + #print('zc=', zc, 'zStartRes=', zStartRes, 'zEndRes=', zEndRes) + + zRangeRes = zEndRes - zStartRes + + izStartRes = int(round((zStartRes - zBegOrig)/zStep)) + if(izStartRes < 0): izStartRes = 0 + + izEndRes = int(round((zEndRes - zBegOrig)/zStep)) + if(izEndRes >= nz): izEndRes = nz - 1 + + if(izEndRes < izStartRes): izEndRes = izStartRes + + zRangeRes = (izEndRes - izStartRes)*zStep #OC04082016 + + nzRes = izEndRes - izStartRes + 1 + nTot = perZ*nzRes + auxList = [0]*nTot + arBxRes = None if(arBxOrig is None) else array('d', auxList) + arByRes = None if(arByOrig is None) else array('d', auxList) + arBzRes = None if(arBzOrig is None) else array('d', auxList) + + for iz in range(izStartRes, izEndRes + 1): + iz_perZ = iz*perZ + iz0_perZ = (iz - izStartRes)*perZ + for iy in range(ny): + iy_nx_p_iz_perZ = iy*nx + iz_perZ + iy_nx_p_iz0_perZ = iy*nx + iz0_perZ + + for ix in range(nx): + i = ix + iy_nx_p_iz_perZ + i0 = ix + iy_nx_p_iz0_perZ + if(arBxOrig is not None): arBxRes[i0] = arBxOrig[i] + if(arByOrig is not None): arByRes[i0] = arByOrig[i] + if(arBzOrig is not None): arBzRes[i0] = arBzOrig[i] + + if(_dupl==True): + return SRWLMagFld3D(_arBx=arBxRes, _arBy=arByRes, _arBz=arBzRes, _nx=nx, _ny=ny, _nz=nzRes, + _rx=_mag3d.rx, _ry=_mag3d.ry, _rz=zRangeRes, _nRep=_mag3d.nRep, _interp=_mag3d.interp) + else: + _mag3d.arBx = arBxRes; _mag3d.arBy = arByRes; _mag3d.arBz = arBzRes; _mag3d.nz = nzRes; _mag3d.rz = zRangeRes + + return _mag3d + +#**************************************************************************** +def srwl_und_find_cen_len(_mag3d, relThrB=0.8): + """ + Finds longitudinal center position and length of undulator (dominating field component) by analyzing its tabulated field. + :param _mag3d: tabulated 3D magnetic field of undulator (object of SRWLMagFld3D type) + :param relThrB: relative threshold to be used with respect to peak field for determining the center + """ + + if((_mag3d is None) or ((_mag3d.arBx is None) and (_mag3d.arBy is None))): + raise Exception("Incorrect definition of the input tabulated undulator magnetic field") + + if((relThrB <= 0.) or (relThrB >= 1.)): + raise Exception("relative threshold to be used with respect to peak field should be larger than 0 and less than 1") + + nx = _mag3d.nx + ny = _mag3d.ny + nz = _mag3d.nz + if(nz <= 1): raise Exception("1D magnetic field with more than one grid point vs longitudinal position is expected") + if((nx > 1) or (ny > 1)): raise Exception("1D magnetic field with more than one grid point vs longitudinal position and one point vs horizontal and vertical position is expected") + + BxIsDefined = False + if(_mag3d.arBx is not None): + if(len(_mag3d.arBx) == nz): BxIsDefined = True + + ByIsDefined = False + if(_mag3d.arBy is not None): + if(len(_mag3d.arBy) == nz): ByIsDefined = True + + if((BxIsDefined == False) and (ByIsDefined == False)): + raise Exception("1D magnetic field data (vertical or horizontal component) are not defined") + + absBxMax = 0. + absByMax = 0. + for iz in range(nz): + if(BxIsDefined): + curAbsB = abs(_mag3d.arBx[iz]) + if(absBxMax < curAbsB): absBxMax = curAbsB + if(ByIsDefined): + curAbsB = abs(_mag3d.arBy[iz]) + if(absByMax < curAbsB): absByMax = curAbsB + + if((absBxMax <= 0.) and (absByMax <= 0.)): + raise Exception("Non-zero 1D magnetic field data (vertical or horizontal component) are not defined") + + arB = None + absBmax = 0. + if(absByMax >= absBxMax): + arB = _mag3d.arBy + absBmax = absByMax + else: + arB = _mag3d.arBx + absBmax = absBxMax + + absThreshB = relThrB*absBmax + zHalfRange = 0.5*_mag3d.rz + zThreshLeft = -zHalfRange + zThreshRight = zHalfRange + zStep = _mag3d.rz/(nz - 1) + + z = zThreshLeft + for iz in range(nz): + curAbsB = abs(arB[iz]) + if(curAbsB >= absThreshB): + zThreshLeft = z + break + z += zStep + + nz_mi_1 = nz - 1 + z = zThreshRight + for iz in range(nz): + curAbsB = abs(arB[nz_mi_1 - iz]) + if(curAbsB >= absThreshB): + zThreshRight = z + break + z -= zStep + + #print(zThreshLeft, zThreshRight) + if(zThreshRight <= zThreshLeft): + return 0., _mag3d.rz + else: + return 0.5*(zThreshRight + zThreshLeft), zThreshRight - zThreshLeft + +#**************************************************************************** +def srwl_und_fld_1d_mis(_mag3d, _per, _dg_by_len, _c1, _c2=0, _g0=0, _a=0, _y0=0, _dydz=0, _z0=None, _dupl=False): + """ + Simulates effects of gap taper and electron "mis-steering" on magnetic field "seen" by the electron, using the formula: + + B(z) = B0(z)*exp(-(dg/(len*per))*(c1 - 2*c2*g0/per)*(z-z0) + c2*(dg/(len*per))^2*(z-z0)^2)*cosh((2*pi*a/per)*(y0+dydz*(z-z0))) + + :param _mag3d: tabulated 3D magnetic field of undulator (object of SRWLMagFld3D type) + :param _per: undulator period [m] + :param _dg_by_len: ratio of gap variation betweein undulator exit and entrance to the undulator length (i.e. dg/len) + :param _c1: coefficient before linear term in the argument of exponent describing the gap dependence (i.e. c1 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _c2: coefficient before quadratic term in the argument of exponent describing the gap dependence (i.e. c2 in b0*exp(-c1*gap/per + c2*(gap/per)^2)) + :param _g0: approximate undulator gap [m] + :param _a: coefficient in the argument of cosh defining dependence of the magnetic field on the vertical position (i.e. a in cosh(2*pi*a*y/per)) + :param _y0: initial vertical position of electron (i.e. at z0 or in the center of the mag3d range) [m] + :param _dydz: vertical angle of electron [rad] + :param _z0: longitudinal position where y0 is defined (if z0 == None, then the center of the mag3d range is assumed) [m] + :param _dupl: switch specifying whether the magnetic field object has to be duplicated or modified in place + :returns: updated 3d magnetic field structure + """ + + if((_mag3d is None) or ((_mag3d.arBx is None) and (_mag3d.arBy is None)) or (_per <= 0.)): + raise Exception("Incorrect definition of the input tabulated undulator magnetic field") + + resMag3D = deepcopy(_mag3d) if(_dupl == True) else _mag3d + + nx = resMag3D.nx + ny = resMag3D.ny + nz = resMag3D.nz + + if(nz <= 1): raise Exception("1D magnetic field with more than one grid point vs longitudinal position is expected") + if((nx > 1) or (ny > 1)): raise Exception("1D magnetic field with more than one grid point vs longitudinal position and one point vs horizontal and vertical position is expected") + + arB = resMag3D.arBy + BorigIsDefined = True + if(arB is None): + BorigIsDefined = False + elif(len(arB) < nz): + BorigIsDefined = False + + if(BorigIsDefined == False): + arB = resMag3D.arBx + if(arB is not None): + if(len(arB) == nz): BorigIsDefined = True + + if(BorigIsDefined == False): raise Exception("1D magnetic field data (vertical or horizontal component) is not defined") + + zStep = resMag3D.rz/(nz - 1) + zRange = resMag3D.rz + if(zRange <= 0): return resMag3D + + #z0 = _z0 if(_z0 != None) else 0. + z0 = _z0 if(_z0 is not None) else srwl_und_find_cen_len(resMag3D)[0] + #print(z0) + + z = -0.5*zRange + for iz in range(nz): + dz = z - z0 + #print(dz) + + dz_dg_d_len_per = dz*_dg_by_len/_per + argExp = -dz_dg_d_len_per*(_c1 + _c2*(dz_dg_d_len_per - 2*_g0/_per)) + argCosh = (6.283185307*_a/_per)*(_y0 + _dydz*dz) + mult = exp(argExp)*cosh(argCosh) + #print(mult) + + arB[iz] *= mult + z += zStep + + return resMag3D + +#**************************************************************************** +def aux_sort_file_list(_lst1, _lst2): + if(_lst1[0] < _lst2[0]): return True + else: return False + +#**************************************************************************** +def srwl_uti_und_gen_file_names_for_conv(_ifln, _ofn_core=None, _pref_gap=None, _pref_mode=None, _pref_phase=None, _dict_mode=None, _order_gmp='gmp'): + """ + Generates list of file name for conversion of magnetic measurements data to SRW format + :param _ifln: name of input folder with magnetic measurements data files + :param _ofn_core: name core for processed data files + :param _pref_gap: list of prefixes and postfixes for recognizing Gap values in the input magn. meas. data file names (it overrides the default definitions) + :param _pref_mode: list of prefixes and postfixes for recognizing Phase Mode values in the input magn. meas. data file names (it overrides the default definitions) + :param _pref_phase: list of prefixes and postfixes for recognizing Phase values in the input magn. meas. data file names (it overrides the default definitions) + :param _dict_mode: list of Phase Mode dictionary for changing the Phase Mode values in the processed file names (and summary file) + :returns: list of lists [[old_fn, new_fn, gap, phase_mode, phase],...] + """ + + #Default output File Name Core + resFileNameCoreDef = 'und' + + #Default Gap, Mode, Phase prefixes and postfixes + prefGapDef = [['G', 'g'], ['m', 'M']] + prefModeDef = [['m', 'M'], ['Ph', 'ph']] + prefPhaseDef = [['Ph', 'ph'], ['.txt']] + + #Default Mode names + lstDictModeDef = [['P', 'p1'], ['p', 'p1'], ['A', 'a1'], ['a', 'a1'], ['M0', 'p1'], ['M1', 'p2'], ['M2', 'a1'], ['M3', 'a2'], ['m0', 'p1'], ['m1', 'p2'], ['m2', 'a1'], ['m3', 'a2']] + + strErrNoGapFound = "Undulator Gap value was not recognized in flle name" + strErrNoModeFound = "Undulator Phase Mode value was not recognized in flle name" + strErrNoPhaseFound = "Undulator Phase value was not recognized in flle name" + + resFileNameCore = resFileNameCoreDef if(_ofn_core is None) else _ofn_core + + prefGap = prefGapDef if(_pref_gap is None) else _pref_gap + prefMode = prefModeDef if(_pref_mode is None) else _pref_mode + prefPhase = prefPhaseDef if(_pref_phase is None) else _pref_phase + + lstDictMode = lstDictModeDef if(_dict_mode is None) else _dict_mode + + numGapPref = len(prefGap[0]); numGapPost = len(prefGap[1]) + numModePref = len(prefMode[0]); numModePost = len(prefMode[1]) + numPhasePref = len(prefPhase[0]); numPhasePost = len(prefPhase[1]) + print(prefGap[0], prefGap[1]) + + lstRes = [] + for root, dirs, files in os.walk(_ifln): + for fnOrig in files: + + #print(fnOrig) + lenFnOrigMi1 = len(fnOrig) - 1 + + iGapStart = -1 + for j in range(numGapPref): + iGapStart0 = fnOrig.find(prefGap[0][j]) + if(iGapStart0 >= 0): iGapStart = iGapStart0 + len(prefGap[0][j]) + #print(iGapStart0) + if(iGapStart >= 0): break + if((iGapStart < 0) or (iGapStart > lenFnOrigMi1)): raise Exception(strErrNoGapFound) + + for j in range(numGapPost): + iGapEnd = fnOrig.find(prefGap[1][j], iGapStart + 1) + if(iGapEnd >= 0): break + if((iGapEnd < 0) or (iGapEnd > lenFnOrigMi1)): raise Exception(strErrNoGapFound) + + gap = float(fnOrig[iGapStart:iGapEnd]) + #print(gap) + + modeFin = '' + iTestModeIsThere = _order_gmp.find('m') + if((iTestModeIsThere >= 0) and (iTestModeIsThere < 3)): + + iModeStart = -1 + iModeStartSearch = 0 + if(_order_gmp == 'gmp'): iModeStartSearch = iGapEnd + #print(iModeStartSearch) + + for j in range(numModePref): + #print(prefMode[0][j]) + iModeStart0 = fnOrig.find(prefMode[0][j], iModeStartSearch) + if(iModeStart0 >= 0): iModeStart = iModeStart0 + len(prefMode[0][j]) + if(iModeStart >= 0): break + #if((iModeStart >= 0) and (not ((iGapStart <= iModeStart) and (iModeStart <= iGapEnd)))): + # print(iModeStart) + # break + + if((iModeStart < 0) or (iModeStart > lenFnOrigMi1)): raise Exception(strErrNoModeFound) + #if((iGapStart <= iModeStart) and (iModeStart <= iGapEnd)): + + for j in range(numModePost): + iModeEnd = fnOrig.find(prefMode[1][j], iModeStart + 1) + if(iModeEnd >= 0): break + if((iModeEnd < 0) or (iModeEnd > lenFnOrigMi1)): raise Exception(strErrNoModeFound) + + modeOrig = fnOrig[iModeStart:iModeEnd] + modeFin = modeOrig + for k in range(len(lstDictMode)): + if(modeOrig == lstDictMode[k][0]): + modeFin = lstDictMode[k][1] + break + + #print(modeOrig, modeFin) + + phase = '' + iTestPhaseIsThere = _order_gmp.find('p') + if((iTestPhaseIsThere >= 0) and (iTestPhaseIsThere < 3)): + + iPhaseStart = -1 + iPhaseStartSearch = 0 + if(_order_gmp == 'gmp'): iModeStartSearch = iModeEnd + elif(_order_gmp == 'gpm'): iModeStartSearch = iGapEnd + + for j in range(numPhasePref): + iPhaseStart0 = fnOrig.find(prefPhase[0][j], iPhaseStartSearch) + if(iPhaseStart0 >= 0): iPhaseStart = iPhaseStart0 + len(prefPhase[0][j]) + if(iPhaseStart >= 0): break + if((iPhaseStart < 0) or (iPhaseStart > lenFnOrigMi1)): raise Exception(strErrNoPhaseFound) + + for j in range(numPhasePost): + iPhaseEnd = fnOrig.find(prefPhase[1][j], iPhaseStart + 1) + if(iPhaseEnd >= 0): break + if((iPhaseEnd < 0) or (iPhaseEnd > lenFnOrigMi1)): raise Exception(strErrNoPhaseFound) + + phase = float(fnOrig[iPhaseStart:iPhaseEnd]) + + fnRes = resFileNameCore + '_g' + str(gap) #+ '_m' + modeFin + '_ph' + str(phase) + + listVal = [fnOrig, fnRes, gap] + + if(modeFin is not ''): + fnRes += '_m' + modeFin + listVal.append(modeFin) + + if(phase is not ''): + fnRes += '_ph' + str(phase) + listVal.append(phase) + + fnRes = fnRes.replace('.', '_') + fnRes += '.dat' + + listVal[1] = fnRes + #print(fnRes) + + #print('gap=', gap, ' mode=', modeFin, ' phase=', phase, fnOrig, fnRes) + #lstRes.append([gap, modeFin, phase, fnOrig, fnRes]) + #lstRes.append([fnOrig, fnRes, gap, modeFin, phase]) + lstRes.append(listVal) + + #lstRes = sorted(lstRes, key=lambda elem: elem[0]) + from operator import itemgetter #, attrgetter, methodcaller + #lstRes = sorted(lstRes, key=itemgetter(0, 1, 2)) + #lstRes = sorted(lstRes, key=itemgetter(2, 3, 4)) + + iTestPhaseIsThere = _order_gmp.find('p') + if((iTestPhaseIsThere >= 0) and (iTestPhaseIsThere < 3)): + lstRes = sorted(lstRes, key=itemgetter(4)) + + iTestModeIsThere = _order_gmp.find('m') + if((iTestModeIsThere >= 0) and (iTestModeIsThere < 3)): + lstRes = sorted(lstRes, key=itemgetter(3)) + + lstRes = sorted(lstRes, key=itemgetter(2)) + + for i in range(len(lstRes)): + print(lstRes[i]) + + return lstRes + +#**************************************************************************** +def srwl_uti_und_conv_meas_fld(_ifn): + """ + Convert magnetic measurement ASCII data file to SRW ASCII format + :param _ifn: name of input magnetic measurements data file + :returns: SRWL magnetic field container with one 3D converted field + """ + + fldDataCols = srwl_uti_read_data_cols(_ifn, '\t') + + arZ = array('d', fldDataCols[0]) + for i in range(len(arZ)): + arZ[i] *= 0.001 + + arBX = array('d', fldDataCols[1]) + arBY = array('d', fldDataCols[2]) + arBZ = array('d', fldDataCols[3]) + + zNp = len(arZ) + zSt = arZ[0] #*0.001 + zFi = arZ[zNp - 1] #*0.001 + + #Field tabulated on Irregular Mesh: + #fldCntIrreg = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt, _interp=2, _arX=None, _arY=None, _arZ=arZ), 0., 0., 0.5*(zSt + zFi)) + fldCntIrreg = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt, _interp=2, _arX=None, _arY=None, _arZ=arZ), 0., 0., 0.) + + #Re-calculating the Field on Regular Mesh: + #fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., zcRes) #OC22062017 + fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., 0.5*(zSt + zFi)) + #fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., 0.) + srwl.CalcMagnField(fldCnt, fldCntIrreg, [0]) + + return fldCnt + +#**************************************************************************** +def srwl_uti_und_proc_one_fld(_opt): + """ + Applies field processing options to a 3D field in container + :param _opt: conversion / processing options structure + """ + + fldCnt = None + + if(_opt.do_conv_fld): + fldCnt = srwl_uti_und_conv_meas_fld(_opt.ifn) + + if(fldCnt is None): fldCnt = srwl_uti_read_mag_fld_3d(_opt.ifn) + + fld3d = fldCnt.arMagFld[0] + zc = fldCnt.arZc[0] + if(_opt.ozc < 1.e+23): + zc = _opt.ozc + fldCnt.arZc[0] = _opt.ozc + + if((_opt.dbx != 0.) or (_opt.dby != 0.) or (_opt.dbz != 0.)): + srwl_und_fld_add_const(fld3d, fldCnt.arZc[0], _opt.dzc, _opt.dzr, _opt.dbx, _opt.dby, _opt.dbz) + #print(2) + + zk = _opt.zk + + if(_opt.do_cor_fld_int): + #zc = fldCnt.arZc[0] + if(zk >= 1.e+22): + zk, auxUndLen = srwl_und_find_cen_len(fld3d) + #print('zk=', zk) + + srwl_und_cor_fld_int(fld3d, _opt.dbwk, _opt.rmsk, zk, zc) + #print(3) + + if(_opt.rz > 0.): #Cutting the field + if(zk >= 1.e+22): + zk, auxUndLen = srwl_und_find_cen_len(fld3d) + + srwl_und_cut_fld(fld3d, _opt.rz, zk) + zc += zk #Because after the cutting zk becomes 0! + #print(4) + + if(len(_opt.ofn) > 0): + + fld3d.save_ascii(_opt.ofn, 0., 0., zc) + #print('zc=', zc) + #print(5) + + if(len(_opt.otfn) > 0): + #z0 = opt.z0t if(opt.z0t != 1.e+23) else fldCnt.arZc[0] - 0.5*fld3d.rz + z0 = _opt.z0t if(_opt.z0t != 1.e+23) else zc - 0.5*fld3d.rz + + elec = SRWLParticle(_x=_opt.x0t, _y=_opt.y0t, _z=z0, _xp=_opt.xp0t, _yp=_opt.yp0t, _gamma=_opt.elen/0.51099890221e-03) + #traj = SRWLPrtTrj(_np=fld3d.nz, _ctStart=0, _ctEnd=fld3d.rz, _partInitCond=elec) + traj = SRWLPrtTrj(_ctStart=0, _ctEnd=fld3d.rz, _partInitCond=elec) + traj.allocate(_np=fld3d.nz, _allB=True) + #print(fld3d.arBy) + srwl.CalcPartTraj(traj, fldCnt, [1]) + traj.save_ascii(_opt.otfn) + #print(6) + +#**************************************************************************** +def srwl_uti_und_conv_proc_fld_file_list(_lst_fn, _opt): + """ + Convert magnetic measurement ASCII data file to SRW ASCII format according to the list + :param _lst_par_fn: list of [old_fn, new_fn] + :param _opt: conversion / processing options structure + """ + + inFileDir = copy(_opt.ifn) + outFileDir = copy(_opt.ofn) + + for i in range(len(_lst_fn)): + + curFileNames = _lst_fn[i] + + print(inFileDir, curFileNames[0]) + print(outFileDir, curFileNames[1]) + + _opt.ifn = os.path.join(inFileDir, curFileNames[0]) + _opt.ofn = os.path.join(outFileDir, curFileNames[1]) + _opt.do_conv_fld = True + + srwl_uti_und_proc_one_fld(_opt) + + _opt.ifn = inFileDir + _opt.ofn = outFileDir + +#**************************************************************************** +def srwl_uti_und_make_sum_file(_lst_fn_par, _odn, _sum_fn_core='und'): + """ + Generate converted magnetic field summary file + :param _lst_fn_par: list of [old_fn, new_fn, gap, phase_mode, phase] + :param _odn: output directory (folder) name + :param _sum_fn_core: core of the summary file name + """ + + resFileName = _sum_fn_core + "_sum.txt" + resFilePath = os.path.join(_odn, resFileName) + + resText = '' + for i in range(len(_lst_fn_par)): + curFileInf = _lst_fn_par[i] + + #print(len(curFileInf)) + lenCurFileInf = len(curFileInf) + if(lenCurFileInf == 5): + resText += str(curFileInf[2]) + '\t' + curFileInf[3] + '\t' + str(curFileInf[4]) + '\t' + curFileInf[1] + '\t1\t1\n' + elif(lenCurFileInf == 3): + resText += str(curFileInf[2]) + '\tp1\t0\t' + curFileInf[1] + '\t1\t1\n' + + uti_io.write_text(resText, resFilePath) + +#**************************************************************************** +#def srwl_fld_extrap_grad_off_mid_plane(_mag_mid, _ry, _ny, _grad_mult=1): +# """ +# Extrapolates magnetic field off horizontal mid-plane based on field gradient in the mid-plane (e.g. for dipole with gradient or for a guad). +# :param _mag_mid: input tabulated 3D magnetic field on 2D mesh vs x and z in the horizontal mid-plane in a container (object of SRWLMagFldC type) +# :param _ry: vertical position range of the final 3D mesh [m] +# :param _ny: number of points vs vertical position in the final 3D mesh +# :param _grad_mult: a number the gradient has to be multiplied by +# :returns: resulting exrapolated 3D magnetic field structure in a container (object of SRWLMagFldC type) +# """ + +# if((_mag_mid is None) or (_mag_mid.arMagFld is None) or (len(_mag_mid.arMagFld) != 1) or (_ry < 0.) or (_ny <= 1)): +# raise Exception("Incorrect input parameters for magnetic field to be extrapolated") + +# fld3d_mid = _mag_mid.arMagFld[0] +# #arBx_mid = fld3d_mid.arBx +# arBy_mid = fld3d_mid.arBy +# arBz_mid = fld3d_mid.arBz + +# xc = _mag_mid.arXc[0] +# xStart = xc - 0.5*fld3d_mid.rx +# nx = fld3d_mid.nx +# xStep = fld3d_mid.rx/(nx - 1) + +# yc = 0 +# yStart = -0.5*_ry +# ny = int(_ny) +# yStep = _ry/(ny - 1) + +# zc = _mag_mid.arZc[0] +# zStart = zc - 0.5*fld3d_mid.rz +# nz = fld3d_mid.nz +# zStep = fld3d_mid.rz/(nz - 1) + +# nTotRes = int(nx*ny*nz) +# arBxRes = array('d', [0]*nTotRes) +# arByRes = array('d', [0]*nTotRes) +# arBzRes = None if(arBz_mid is None) else array('d', [0]*nTotRes) + +# nx_mi_1 = nx - 1 +# #print(nx, xStart, xStep, ny, yStart, yStep, nz, zStart, zStep) + +# for iz in range(nz): +# iz_nx = iz*nx +# iz_nx_ny = iz*nx*ny +# for ix in range(nx): +# b1y = 0; b2y = 0; b0y = 0; dx = xStep +# if(ix == 0): +# b1y = arBy_mid[iz_nx] +# b2y = arBy_mid[iz_nx + 1] +# b0y = b1y +# elif(ix == nx_mi_1): +# b1y = arBy_mid[iz_nx + nx_mi_1 - 1] +# b2y = arBy_mid[iz_nx + nx_mi_1] +# b0y = b2y +# else: +# b1y = arBy_mid[iz_nx + ix - 1] +# b0y = arBy_mid[iz_nx + ix] +# b2y = arBy_mid[iz_nx + ix + 1] +# dx = 2*xStep + +# curGrad = _grad_mult*(b2y - b1y)/dx +# y = yStart +# for iy in range(ny): +# ofst = iz_nx_ny + iy*nx + ix +# arBxRes[ofst] = y*curGrad +# arByRes[ofst] = b0y +# y += yStep + +# fld3dRes = SRWLMagFld3D(arBxRes, arByRes, arBzRes, nx, ny, nz, fld3d_mid.rx, _ry, fld3d_mid.rz) +# #print(fld3dRes.nx, fld3dRes.rx, fld3dRes.ny, fld3dRes.ry, fld3dRes.nz, fld3dRes.rz) +# return SRWLMagFldC(fld3dRes, xc, yc, zc) + +#**************************************************************************** +##def srwl_fld_extrap_grad_curv(_mag_curv_mid, _cen_trj_data, _xi, _xf, _nx, _yi, _yf, _ny, _zi, _zf, _nz, _grad_mult=1): +## """ +## Extrapolates magnetic field on rectangulat 3D mesh in and off horizontal mid-plane based on field gradient in the mid-plane (e.g. for dipole with gradient or for a guad). +## :param _mag_curv_mid: input tabulated 3D magnetic field on 2D mesh vs x and z in Natural frame in the horizontal mid-plane in a container (object of SRWLMagFldC type) +## :param _cen_trj_data: central trajectory data defining the Natural frame of the input magnetic field (_cen_trj_data[0] is ct, _cen_trj_data[1] is x. _cen_trj_data[2] is z) +## :param _xi: horizontal initial position of the final 3D mesh [m] +## :param _xf: horizontal final position of the final 3D mesh [m] +## :param _nx: number of points vs horizontal position in the final 3D mesh +## :param _yi: vertical initial position of the final 3D mesh [m] +## :param _yf: vertical initial position of the final 3D mesh [m] +## :param _ny: number of points vs vertical position in the final 3D mesh +## :param _zi: longitudinal initial position of the final 3D mesh [m] +## :param _zf: longitudinal final position of the final 3D mesh [m] +## :param _nz: number of points vs longitudinal position in the final 3D mesh +## :param _grad_mult: a number the gradient has to be multiplied by +## :returns: exrapolated 3D magnetic field structure in a container (object of SRWLMagFldC type) +## """ +## +## if((_mag_curv_mid is None) or (_mag_curv_mid.arMagFld is None) or (len(_mag_curv_mid.arMagFld) < 1) or (_cen_trj_data is None) or (len(_cen_trj_data) < 3) +## or (_nx < 1) or (_ny < 1) or (_nz < 1)): +## raise Exception("Incorrect input parameters for magnetic field to be extrapolated") +## #print('In srwl_fld_extrap_grad_curv') +## +## fld3d_curv_mid = _mag_curv_mid.arMagFld[0] +## #arBx_curv_mid = fld3d_curv_mid.arBx +## arBy_curv_mid = fld3d_curv_mid.arBy +## arBz_curv_mid = fld3d_curv_mid.arBz + +#*********************************Entry point (for command-prompt calls) +if __name__=="__main__": + import optparse + p = optparse.OptionParser() + p.add_option('--cor', dest='do_cor_fld_int', action='store_true', default=False, help="correct 1st and 2nd field integrals of tabulated undulator magnetic field") + p.add_option('--conv', dest='do_conv_fld', action='store_true', default=False, help="convert magnetic measurement data file to SRW ASCII format") + #p.add_option('--trun', dest='do_trunc_fld', action='store_true', default=False, help="truncate magnetic field (i.e. reduce range) vs longitudinal position") + #p.add_option('--efg', dest='do_ext_fld_grd', action='store_true', default=False, help="extrapolate 3D magnetic measurement data out of horizontal mid-plane using gradient") + #p.add_option('--efgc', dest='do_ext_fld_grd_curv', action='store_true', default=False, help="extrapolate 3D magnetic measurement data out of horizontal mid-plane using gradient, assuming input field data is gived for curved path along central trajectory") + + p.add_option('--ifn', dest='ifn', type='string', default='', help="input field file name") + p.add_option('--ofn', dest='ofn', type='string', default='', help="output field file name") + p.add_option('--itfn', dest='itfn', type='string', default='', help="input trajectory file name") + p.add_option('--otfn', dest='otfn', type='string', default='', help="output trajectory file name") + + p.add_option('--ozc', dest='ozc', type="float", default=1.e+23, metavar="NUMBER", help="center longitudinal coordinate of the output magnetic field [m]") #OC22062017 + + p.add_option('--dbwk', dest='dbwk', type="float", default=2.8, metavar="NUMBER", help="distance between correcting kicks [m]") + p.add_option('--rmsk', dest='rmsk', type="float", default=0.05, metavar="NUMBER", help="RMS length of the correcting kicks [m]") + + p.add_option('--rz', dest='rz', type="float", default=0., metavar="NUMBER", help="new longitudinal range of magnetic field after truncation [m] (effective if > 0; the center field will be taken from zk)") + + p.add_option('--zk', dest='zk', type="float", default=1.e+23, metavar="NUMBER", help="longitudinal position of the correcting kicks [m]") + p.add_option('--z0t', dest='z0t', type="float", default=1.e+23, metavar="NUMBER", help="initial longitudinal position for trajectory calculation [m]") + p.add_option('--x0t', dest='x0t', type="float", default=0., metavar="NUMBER", help="initial horizontal position for trajectory calculation [m]") + p.add_option('--y0t', dest='y0t', type="float", default=0., metavar="NUMBER", help="initial vertical position for trajectory calculation [m]") + p.add_option('--xp0t', dest='xp0t', type="float", default=0., metavar="NUMBER", help="initial horizontal angle for trajectory calculation [m]") + p.add_option('--yp0t', dest='yp0t', type="float", default=0., metavar="NUMBER", help="initial vertical angle for trajectory calculation [m]") + p.add_option('--elen', dest='elen', type="float", default=3., metavar="NUMBER", help="electron energy [GeV]") + p.add_option('--dbx', dest='dbx', type="float", default=0., metavar="NUMBER", help="horizontal magnetic field component to add [T]") + p.add_option('--dby', dest='dby', type="float", default=0., metavar="NUMBER", help="vertical magnetic field component to add [T]") + p.add_option('--dbz', dest='dbz', type="float", default=0., metavar="NUMBER", help="longitudinal magnetic field component to add [T]") + p.add_option('--dzc', dest='dzc', type="float", default=0., metavar="NUMBER", help="center longitudinal position for adding constant magnetic field [m]") + p.add_option('--dzr', dest='dzr', type="float", default=0., metavar="NUMBER", help="range of longitudinal position within which to add constant magnetic field [m]") + + #p.add_option('--xi', dest='xi', type="float", default=0., metavar="NUMBER", help="horizontal initial position of the final 3D mesh [m]") + #p.add_option('--xf', dest='xf', type="float", default=0., metavar="NUMBER", help="horizontal final position of the final 3D mesh [m]") + #p.add_option('--nx', dest='nx', type="float", default=0., metavar="NUMBER", help="number of points vs horizontal position in the final 3D mesh") + #p.add_option('--yi', dest='yi', type="float", default=0., metavar="NUMBER", help="vertical initial position of the final 3D mesh [m]") + #p.add_option('--yf', dest='yf', type="float", default=0., metavar="NUMBER", help="vertical final position of the final 3D mesh [m]") + #p.add_option('--ny', dest='ny', type="float", default=0., metavar="NUMBER", help="number of points vs vertical position in the final 3D mesh") + #p.add_option('--zi', dest='zi', type="float", default=0., metavar="NUMBER", help="longitudinal initial position of the final 3D mesh [m]") + #p.add_option('--zf', dest='zf', type="float", default=0., metavar="NUMBER", help="longitudinal final position of the final 3D mesh [m]") + #p.add_option('--nz', dest='nz', type="float", default=0., metavar="NUMBER", help="number of points vs longitudinal position in the final 3D mesh") + + p.add_option('--cnvm', dest='do_conv_many_files', action='store_true', default=False, help="convert magnetic measurement data from multiple files in a folder to SRW ASCII format, apply field integral correction and save to another folder, and save a summary file to the same folder") + p.add_option('--ofnc', dest='out_file_name_core', type='string', default='', help="output file name core") + p.add_option('--prfg', dest='pref_gap', type='string', default='', help="string of coma-separated prefixes for recognizing Gap values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--psfg', dest='postf_gap', type='string', default='', help="string of coma-separated postfixes for recognizing Gap values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--prfm', dest='pref_mode', type='string', default='', help="string of coma-separated prefixes for recognizing Phase Mode values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--psfm', dest='postf_mode', type='string', default='', help="string of coma-separated postfixes for recognizing Phase Mode values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--prfp', dest='pref_phase', type='string', default='', help="string of coma-separated prefixes for recognizing Phase values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--psfp', dest='postf_phase', type='string', default='', help="string of coma-separated postfixes for recognizing Phase values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--igmp', dest='ord_gmp_inp', type='string', default='gmp', help="order of gap-mode-phase in the input file names") + p.add_option('--ipm', dest='in_phase_mode', type='string', default='', help="string of coma-separated Phase Mode values in the input magn. meas. data file names (it overrides the default definitions)") + p.add_option('--opm', dest='out_phase_mode', type='string', default='', help="string of coma-separated Phase Mode values for output data file names (it overrides the default definitions)") + + opt, args = p.parse_args() + + #if(opt.do_ext_fld_grd): #Extrapolate 3D magnetic measurement data out of horizontal mid-plane using gradient + # fldMidPl = srwl_uti_read_mag_fld_3d(opt.ifn) + # fldRes = srwl_fld_extrap_grad_off_mid_plane(fldMidPl, opt.ry, opt.ny) + # fld3dRes = fldRes.arMagFld[0] + # fld3dRes.save_ascii(opt.ofn, fldRes.arXc[0], fldRes.arYc[0], fldRes.arZc[0]) + # sys.exit() + + #if(opt.do_ext_fld_grd_curv): #Extrapolate 3D magnetic measurement data out of horizontal mid-plane using gradient, assuming input field data is gived for curved path along central trajectory" + # fldCurvMidPl = srwl_uti_read_mag_fld_3d(opt.ifn) + # cenTrajDataAll = srwl_uti_read_data_cols(opt.itfn, '\t', _i_col_start=0, _i_col_end=6, _n_line_skip=1) + # #print(len(cenTrajData)) + # cenTrajData_ct_x_z = [cenTrajDataAll[0], cenTrajDataAll[1], cenTrajDataAll[5]] + # fldRes = srwl_fld_extrap_grad_curv(fldCurvMidPl, cenTrajData_ct_x_z, opt.xi, opt.xf, opt.nx, opt.yi, opt.yf, opt.ny, opt.zi, opt.zf, opt.nz) + + # #fld3dRes = fldRes.arMagFld[0] + # #fld3dRes.save_ascii(opt.ofn, fldRes.arXc[0], fldRes.arYc[0], fldRes.arZc[0]) + # sys.exit() + + #print(opt.ifn) + #fldCnt = None + + if(opt.do_conv_many_files): + #Example of this processing: + #python srwl_uti_und.py --cnvm --ifn="Y:\Processed Data to share\EPU105 ESM\HP\Processed Data" --ofn="C:\SoftwareDevelopments\SRW_Dev\env\work\srw_python\data_ESM\magn_meas_epu105" --ofnc="epu105_esm" --cor --ozc=-0.036 --zk=0. --dbwk=2.7 + #or, for planar undulators: + #python srwl_uti_und.py --cnvm --ifn="data_ISR\FieldC" --ofn="data_ISR\magn_meas" --ofnc="ivu23_isr" --cor --ozc=0 --zk=0 --dbwk=2.7 --prfg=X0_Y0_gap --psfg=.txt --igmp=g + #In this case opt.ifn, opt.ofn are used for folder names! + + lstPrefPostfGap = uti_parse.str_to_pair_of_lists(opt.pref_gap, opt.postf_gap) + lstPrefPostfMode = uti_parse.str_to_pair_of_lists(opt.pref_mode, opt.postf_mode) + lstPrefPostfPhase = uti_parse.str_to_pair_of_lists(opt.pref_phase, opt.postf_phase) + lstModeDict = uti_parse.str_to_list_of_pairs(opt.in_phase_mode, opt.out_phase_mode) + #print(lstPrefPostfGap, lstPrefPostfMode, lstPrefPostfPhase, lstModeDict) + + lstParamFileNames = srwl_uti_und_gen_file_names_for_conv(opt.ifn, _ofn_core=opt.out_file_name_core, _pref_gap=lstPrefPostfGap, _pref_mode=lstPrefPostfMode, _pref_phase=lstPrefPostfPhase, _dict_mode=lstModeDict, _order_gmp=opt.ord_gmp_inp) + #print(lstParamFileNames) + srwl_uti_und_conv_proc_fld_file_list(lstParamFileNames, opt) + srwl_uti_und_make_sum_file(lstParamFileNames, opt.ofn, opt.out_file_name_core) + + else: + srwl_uti_und_proc_one_fld(opt) #Process one-file options + +## if(opt.do_conv_fld): #Convertion from magnetic measurements data format +#### fldDataCols = srwl_uti_read_data_cols(opt.ifn, '\t') +#### +#### arZ = array('d', fldDataCols[0]) +#### for i in range(len(arZ)): +#### arZ[i] *= 0.001 +#### +#### arBX = array('d', fldDataCols[1]) +#### arBY = array('d', fldDataCols[2]) +#### arBZ = array('d', fldDataCols[3]) +#### +#### zNp = len(arZ) +#### zSt = arZ[0] #*0.001 +#### zFi = arZ[zNp - 1] #*0.001 +#### +#### #Field tabulated on Irregular Mesh: +#### #fldCntIrreg = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt, _interp=2, _arX=None, _arY=None, _arZ=arZ), 0., 0., 0.5*(zSt + zFi)) +#### fldCntIrreg = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt, _interp=2, _arX=None, _arY=None, _arZ=arZ), 0., 0., 0.) +#### +#### #Re-calculating the Field on Regular Mesh: +#### #fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., zcRes) #OC22062017 +#### fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., 0.5*(zSt + zFi)) +#### #fldCnt = SRWLMagFldC(SRWLMagFld3D(arBX, arBY, arBZ, 1, 1, zNp, 0., 0., zFi - zSt), 0., 0., 0.) +#### srwl.CalcMagnField(fldCnt, fldCntIrreg, [0]) +## +## fldCnt = srwl_uti_und_conv_meas_fld(opt.ifn) +## +## if(fldCnt == None): fldCnt = srwl_uti_read_mag_fld_3d(opt.ifn) +## +## fld3d = fldCnt.arMagFld[0] +## zc = fldCnt.arZc[0] +## if(opt.ozc < 1.e+23): +## zc = opt.ozc +## fldCnt.arZc[0] = opt.ozc +## +## #print(' zc=', zc) +## +## if((opt.dbx != 0.) or (opt.dby != 0.) or (opt.dbz != 0.)): +## srwl_und_fld_add_const(fld3d, fldCnt.arZc[0], opt.dzc, opt.dzr, opt.dbx, opt.dby, opt.dbz) +## #print(2) +## +## zk = opt.zk +## +## if(opt.do_cor_fld_int): +## #zc = fldCnt.arZc[0] +## if(zk >= 1.e+22): +## zk, auxUndLen = srwl_und_find_cen_len(fld3d) +## #print('zk=', zk) +## +## srwl_und_cor_fld_int(fld3d, opt.dbwk, opt.rmsk, zk, zc) +## #print(3) +## +## if(opt.rz > 0.): #Cutting the field +## if(zk >= 1.e+22): +## zk, auxUndLen = srwl_und_find_cen_len(fld3d) +## +## srwl_und_cut_fld(fld3d, opt.rz, zk) +## zc += zk #Because after the cutting zk becomes 0! +## #print(4) +## +## if(len(opt.ofn) > 0): +## +## fld3d.save_ascii(opt.ofn, 0., 0., zc) +## print('zc=', zc) +## #print(5) +## +## if(len(opt.otfn) > 0): +## #z0 = opt.z0t if(opt.z0t != 1.e+23) else fldCnt.arZc[0] - 0.5*fld3d.rz +## z0 = opt.z0t if(opt.z0t != 1.e+23) else zc - 0.5*fld3d.rz +## +## elec = SRWLParticle(_x=opt.x0t, _y=opt.y0t, _z=z0, _xp=opt.xp0t, _yp=opt.yp0t, _gamma=opt.elen/0.51099890221e-03) +## traj = SRWLPrtTrj(_np=fld3d.nz, _ctStart=0, _ctEnd=fld3d.rz, _partInitCond=elec) +## #print(fld3d.arBy) +## srwl.CalcPartTraj(traj, fldCnt, [1]) +## traj.save_ascii(opt.otfn) +## #print(6) + diff --git a/env/release/srw_python/srwlib.py b/env/release/srw_python/srwlib.py index 361f832c..663e902f 100644 --- a/env/release/srw_python/srwlib.py +++ b/env/release/srw_python/srwlib.py @@ -1,5 +1,5 @@ -############################################################################# -# SRWLib for Python v 0.066 +############################################################################# +# SRWLib for Python v 0.14 ############################################################################# from __future__ import print_function #Python 2.7 compatibility @@ -7,10 +7,41 @@ from array import * from math import * from copy import * -#from random import * + +import datetime +import json import random import sys +import os import traceback +import uti_math +import errno +import tempfile +import shutil +import time + +from srwl_uti_cryst import * +#try: +# from uti_plot import * #universal simple plotting module distributed together with SRWLib +#except: +# #excInf = sys.exc_info() +# #print(excInf[1]) #printing exception value +# traceback.print_exc() +# print('Plotting utilities module was not loaded.') +# print('1D and 2D plotting (generation of graphs, image plots, etc.) will not be possible.') + +#**************************************************************************** +#**************************************************************************** +# Global Constants +#**************************************************************************** +#**************************************************************************** +_Pi = 3.14159265358979 +_ElCh = 1.60217646263E-19 #1.602189246E-19 #Electron Charge [Q] +_ElMass_kg = 9.1093818872E-31 #9.10953447E-31 #Electron Mass in [kg] +_ElMass_MeV = 0.51099890221 #Electron Mass in [MeV] +_LightSp = 2.9979245812E+08 #Speed of Light [m/c] +_Light_eV_mu = 1.23984186 #Wavelength <-> Photon Energy conversion constant ([um] <-> [eV]) +_PlanckConst_eVs = 4.13566766225E-15 #Planck constant in [eV*s] #**************************************************************************** #**************************************************************************** @@ -40,6 +71,24 @@ def __init__(self, _x=0, _y=0, _z=0, _xp=0, _yp=0, _gamma=1, _relE0=1, _nq=-1): self.relE0 = _relE0 self.nq = _nq + def drift(self, _dist): + """Propagates particle beam statistical moments over a distance in free space + :param _dist: distance the beam has to be propagated over [m] + """ + self.z += _dist + self.x += self.xp*_dist + self.y += self.yp*_dist + #print('e-beam positions after drift: x=', self.x, ' y=', self.y, ' at z=', self.z) + + def get_E(self, _unit='GeV'): + en = self.gamma*self.relE0*_ElMass_MeV #[MeV] + if _unit == 'TeV': en *= 1e-06 + elif _unit == 'GeV': en *= 1e-03 + elif _unit == 'keV': en *= 1e+03 + elif _unit == 'eV': en *= 1e+06 + elif _unit == 'meV': en *= 1e+09 + return en + #**************************************************************************** class SRWLPartBeam(object): """Particle Beam""" @@ -77,6 +126,69 @@ def __init__(self, _Iavg=0, _nPart=0, _partStatMom1=None, _arStatMom2=None): self.partStatMom1 = SRWLParticle() if _partStatMom1 is None else _partStatMom1 self.arStatMom2 = array('d', [0] * 21) if _arStatMom2 is None else _arStatMom2 + def from_Twiss(self, _Iavg=0, _e=0, _sig_e=0, _emit_x=0, _beta_x=0, _alpha_x=0, _eta_x=0, _eta_x_pr=0, _emit_y=0, _beta_y=0, _alpha_y=0, _eta_y=0, _eta_y_pr=0): + """Sets up particle (electron) beam internal data from Twiss parameters + :param _Iavg: average current [A] + :param _e: energy [GeV] + :param _sig_e: RMS energy spread + :param _emit_x: horizontal emittance [m] + :param _beta_x: horizontal beta-function [m] + :param _alpha_x: horizontal alpha-function [rad] + :param _eta_x: horizontal dispersion function [m] + :param _eta_x_pr: horizontal dispersion function derivative [rad] + :param _emit_y: vertical emittance [m] + :param _beta_y: vertical beta-function [m] + :param _alpha_y: vertical alpha-function [rad] + :param _eta_y: vertical dispersion function [m] + :param _eta_y_pr: vertical dispersion function derivative [rad] + """ + self.Iavg = _Iavg + self.partStatMom1.gamma = _e/0.51099890221e-03 #assuming electrons + sigeE2 = _sig_e*_sig_e + self.arStatMom2[0] = _emit_x*_beta_x + sigeE2*_eta_x*_eta_x #<(x-)^2> + self.arStatMom2[1] = -_emit_x*_alpha_x + sigeE2*_eta_x*_eta_x_pr #<(x-)(x'-)> + self.arStatMom2[2] = _emit_x*(1 + _alpha_x*_alpha_x)/_beta_x + sigeE2*_eta_x_pr*_eta_x_pr #<(x'-)^2> + self.arStatMom2[3] = _emit_y*_beta_y + sigeE2*_eta_y*_eta_y #<(y-)^2> + self.arStatMom2[4] = -_emit_y*_alpha_y + sigeE2*_eta_y*_eta_y_pr #<(y-)(y'-)> + self.arStatMom2[5] = _emit_y*(1 + _alpha_y*_alpha_y)/_beta_y + sigeE2*_eta_y_pr*_eta_y_pr #<(y'-)^2> + self.arStatMom2[10] = sigeE2 + + def from_RMS(self, _Iavg=0, _e=0, _sig_e=0, _sig_x=0, _sig_x_pr=0, _m_xx_pr=0, _sig_y=0, _sig_y_pr=0, _m_yy_pr=0): + """Sets up particle (electron) beam internal data from Twiss parameters + :param _Iavg: average current [A] + :param _e: energy [GeV] + :param _sig_e: RMS energy spread + :param _sig_x: horizontal RMS size [m] + :param _sig_x_pr: horizontal RMS divergence [rad] + :param _m_xx_pr: <(x-)(x'-)> [m] + :param _sig_y: vertical RMS size [m] + :param _sig_y_pr: vertical RMS divergence [rad] + :param _m_yy_pr: <(y-)(y'-)> [m] + """ + self.Iavg = _Iavg + self.partStatMom1.gamma = _e/0.51099890221e-03 #assuming electrons + sigeE2 = _sig_e*_sig_e + self.arStatMom2[0] = _sig_x*_sig_x #<(x-)^2> + self.arStatMom2[1] = _m_xx_pr #<(x-)(x'-)> + self.arStatMom2[2] = _sig_x_pr*_sig_x_pr #<(x'-)^2> + self.arStatMom2[3] = _sig_y*_sig_y #<(y-)^2> + self.arStatMom2[4] = _m_yy_pr #<(y-)(y'-)> + self.arStatMom2[5] = _sig_y_pr*_sig_y_pr #<(y'-)^2> + self.arStatMom2[10] = sigeE2 + + def drift(self, _dist): + """Propagates particle beam statistical moments over a distance in free space + :param _dist: distance the beam has to be propagated over [m] + """ + self.partStatMom1.drift(_dist) + self.arStatMom2[0] += self.arStatMom2[1]*_dist*2 + self.arStatMom2[2]*_dist*_dist + self.arStatMom2[1] += self.arStatMom2[2]*_dist + self.arStatMom2[3] += self.arStatMom2[4]*_dist*2 + self.arStatMom2[5]*_dist*_dist + self.arStatMom2[4] += self.arStatMom2[5]*_dist + #print('E-beam 2nd order moments after drift=', _dist) + #print(self.arStatMom2) + #to be checked and extended for other stat. moments + #**************************************************************************** class SRWLMagFld(object): """Magnetic Field (base class)""" @@ -116,22 +228,53 @@ def __init__(self, _arBx=None, _arBy=None, _arBz=None, _nx=0, _ny=0, _nz=0, _rx= self.nRep = _nRep self.interp = _interp + def add_const(self, _bx=0, _by=0, _bz=0): + """Adds constant magnetic field to the entire tabulated field (to simulate e.g. background magnetic field effects) + :param _bx: horizontal magnetic field component to add [T] + :param _by: vertical magnetic field component to add [T] + :param _bz: longitudinal magnetic field component to add [T] + """ + nTot = self.nx*self.ny*self.nz + for i in range(nTot): + self.arBx[i] += _bx + self.arBy[i] += _by + self.arBz[i] += _bz + + def save_ascii(self, _file_path, _xc=0, _yc=0, _zc=0): + """Auxiliary function to write tabulated Arbitrary 3D Magnetic Field data to ASCII file""" + sHead = '#Bx [T], By [T], Bz [T] on 3D mesh: inmost loop vs X (horizontal transverse position), outmost loop vs Z (longitudinal position)\n' + sHead += '#' + repr(-0.5*self.rx + _xc) + ' #initial X position [m]\n' + sHead += '#' + repr(0. if(self.nx <= 1) else self.rx/(self.nx - 1)) + ' #step of X [m]\n' + sHead += '#' + repr(self.nx) + ' #number of points vs X\n' + sHead += '#' + repr(-0.5*self.ry + _yc) + ' #initial Y position [m]\n' + sHead += '#' + repr(0. if(self.ny <= 1) else self.ry/(self.ny - 1)) + ' #step of Y [m]\n' + sHead += '#' + repr(self.ny) + ' #number of points vs Y\n' + sHead += '#' + repr(-0.5*self.rz + _zc) + ' #initial Z position [m]\n' + sHead += '#' + repr(0. if(self.nz <= 1) else self.rz/(self.nz - 1)) + ' #step of Z [m]\n' + sHead += '#' + repr(self.nz) + ' #number of points vs Z\n' + arColsWr = [self.arBx, self.arBy, self.arBz] + #print(self.nx, self.rx, self.ny, self.ry, self.nz, self.rz) + srwl_uti_write_data_cols(_file_path, arColsWr, '\t', sHead) + class SRWLMagFldM(SRWLMagFld): """Magnetic Field: Multipole Magnet""" - def __init__(self, _G=0, _m=2, _n_or_s='n', _Leff=0, _Ledge=0): + #def __init__(self, _G=0, _m=2, _n_or_s='n', _Leff=0, _Ledge=0): + def __init__(self, _G=0, _m=2, _n_or_s='n', _Leff=0, _Ledge=0, _R=0): """ :param _G: field parameter [T] for dipole, [T/m] for quadrupole (negative means defocusing for x), [T/m^2] for sextupole, [T/m^3] for octupole :param _m: multipole order 1 for dipole, 2 for quadrupoole, 3 for sextupole, 4 for octupole :param _n_or_s: normal ('n') or skew ('s') :param _Leff: effective length [m] :param _Ledge: "soft" edge length for field variation from 10% to 90% [m]; G/(1 + ((z-zc)/d)^2)^2 fringe field dependence is assumed + :param _R: radius of curvature of central trajectory [m] (for simulating e.g. quadrupole component integrated to a bending magnet; effective if > 0) """ self.G = _G self.m = _m self.n_or_s = _n_or_s self.Leff = _Leff self.Ledge = _Ledge + self.R = _R class SRWLMagFldS(SRWLMagFld): """Magnetic Field: Solenoid""" @@ -177,34 +320,267 @@ def __init__(self, _arHarm=None, _per=0, _nPer=0): self.nPer = _nPer def allocate(self, _nHarm): - self.arHarm = [SRWLMagFldH()]*_nHarm + #self.arHarm = [SRWLMagFldH()]*_nHarm + arHarmLoc = [] + for i in range(_nHarm): arHarm.append(SRWLMagFldH()) + + def set_sin(self, _per=0.02, _len=1, _bx=0, _by=0, _phx=0, _phy=0, _sx=1, _sy=1): + """Setup basic undulator with sinusoidal magnetic field + :param _per: period length [m] + :param _len: undulator length [m] + :param _bx: horizontal magnetic field amplitude [m] + :param _by: vertical magnetic field amplitude [m] + :param _phx: initial phase of the horizontal magnetic field [rad] + :param _phx: initial phase of the vertical magnetic field [rad] + :param _sx: symmetry of the horizontal magnetic field vs longitudinal position 1 - symmetric (B ~ cos(2*Pi*n*z/per + ph)) , -1 - anti-symmetric (B ~ sin(2*Pi*n*z/per + ph)) + :param _sy: symmetry of the vertical magnetic field vs longitudinal position + """ + nPerAvg = int(round(_len/_per)) + self.nPer = nPerAvg + self.per = _per + if(len(self.arHarm) > 0): + del self.arHarm; self.arHarm = [] + if(_bx != 0): self.arHarm.append(SRWLMagFldH(_h_or_v='h', _B=_bx, _ph=_phx, _s=_sx)) + if(_by != 0): self.arHarm.append(SRWLMagFldH(_h_or_v='v', _B=_by, _ph=_phy, _s=_sy)) + + def get_K(self): + """Estimate K (deflection parameter) value""" + mult = _ElCh/(2.*_Pi*_ElMass_kg*_LightSp) + nHarm = len(self.arHarm) + sumBdNe2 = 0 + for i in range(nHarm): + curHarm = self.arHarm[i] + curBdN = curHarm.B/curHarm.n + sumBdNe2 += curBdN*curBdN + return mult*self.per*sqrt(sumBdNe2) + + def K_2_B(self, K): #MR31072016 (added) + """Convert K (deflection parameter) to B (magnetic field amplitude)""" + mult = _ElCh/(2.*_Pi*_ElMass_kg*_LightSp) + B = K / (mult * self.per) + return B + + def get_E1(self, _en_elec=3., _unit='eV'): + """Estimate fundamental photon energy + :param _en_elec: electron energy [GeV] + :return: fundamental photon energy [eV] + """ + K = self.get_K() + gamma = 1000.*_en_elec/_ElMass_MeV + lamda_m = self.per*(1. + 0.5*K*K)/(2.*gamma*gamma) + return srwl_uti_ph_en_conv(lamda_m, _in_u='m', _out_u=_unit) + + def E1_2_K(self, _e1, _en_elec=3.): + """Estimate deflection parameter from + :param _e1: fundamental photon energy [eV] + :param _en_elec: electron energy [GeV] + :return: deflection parameter + """ + buf = 9.4963421866853*_en_elec*_en_elec/self.per/_e1 + if(buf < 1): return 0 + else: return sqrt((buf - 1)*2) + + def E1_2_B(self, _e1, _en_elec=3.): + """Estimate deflection parameter from + :param _e1: fundamental photon energy [eV] + :param _en_elec: electron energy [GeV] + :return: magnetic field amplitude [T] + """ + K = self.E1_2_K(_e1, _en_elec) + return 2*_Pi*_ElMass_kg*_LightSp*K/(_ElCh*self.per) class SRWLMagFldC(SRWLMagFld): """Magnetic Field: Container""" - def __init__(self, _arMagFld=None, _arXc=None, _arYc=None, _arZc=None): + def __init__(self, _arMagFld=None, _arXc=None, _arYc=None, _arZc=None, _arVx=None, _arVy=None, _arVz=None, _arAng=None): + #def __init__(self, _arMagFld=None, _arXc=None, _arYc=None, _arZc=None): """ :param _arMagFld: magnetic field structures array :param _arXc: horizontal center positions of magnetic field elements in arMagFld array [m] :param _arYc: vertical center positions of magnetic field elements in arMagFld array [m] :param _arZc: longitudinal center positions of magnetic field elements in arMagFld array [m] + :param _arVx: horizontal components of axis vectors of magnetic field elements in arMagFld array [rad] + :param _arVy: vertical components of axis vectors of magnetic field elements in arMagFld array [rad] + :param _arVz: longitudinal components of axis vectors of magnetic field elements in arMagFld array [rad] + :param _arAng: rotation angles of magnetic field elements about their axes [rad] """ - self.arMagFld = [] if _arMagFld is None else _arMagFld - self.arXc = array('d') if _arXc is None else _arXc - self.arYc = array('d') if _arYc is None else _arYc - self.arZc = array('d') if _arZc is None else _arZc + #self.arMagFld = [] if _arMagFld is None else _arMagFld + + if(_arMagFld is None): + self.arMagFld = [] + self.arXc = array('d') if _arXc is None else _arXc + self.arYc = array('d') if _arYc is None else _arYc + self.arZc = array('d') if _arZc is None else _arZc + #The following arrays are optional + #self.arVx = array('d') if _arVx is None else _arVx + #self.arVy = array('d') if _arVy is None else _arVy + #self.arVz = array('d') if _arVz is None else _arVz + #self.arAng = array('d') if _arAng is None else _arAng + else: + if(not(isinstance(_arMagFld, list) or isinstance(_arMagFld, array) or isinstance(_arMagFld, tuple))): + self.arMagFld = [_arMagFld] #to allow for simple initialization by one element + nElem = 1 + else: + self.arMagFld = _arMagFld + nElem = len(_arMagFld) + + if(_arXc is None): + self.arXc = array('d', [0]*nElem) + elif(isinstance(_arXc, array)): + self.arXc = _arXc + elif(isinstance(_arXc, list)): #or isinstance(_arXc, tuple)): + self.arXc = array('d', _arXc) + elif(nElem == 1): + self.arXc = array('d', [0]) + self.arXc[0] = _arXc + + if(_arYc is None): + self.arYc = array('d', [0]*nElem) + #elif(isinstance(_arYc, list) or isinstance(_arYc, array) or isinstance(_arYc, tuple)): + # self.arYc = _arYc + elif(isinstance(_arYc, array)): + self.arYc = _arYc + elif(isinstance(_arYc, list)): #or isinstance(_arYc, tuple)): + self.arYc = array('d', _arYc) + elif(nElem == 1): + self.arYc = array('d', [0]) + self.arYc[0] = _arYc + + if(_arZc == None): + self.arZc = array('d', [0]*nElem) + #elif(isinstance(_arZc, list) or isinstance(_arZc, array) or isinstance(_arZc, tuple)): + # self.arZc = _arZc + elif(isinstance(_arZc, array)): + self.arZc = _arZc + elif(isinstance(_arZc, list)): #or isinstance(_arZc, tuple)): + self.arZc = array('d', _arZc) + elif(nElem == 1): + self.arZc = array('d', [0]) + self.arZc[0] = _arZc + + arVxWasSubm = False + if(_arVx is None): + self.arVx = array('d', [0]*nElem) + elif(isinstance(_arVx, array)): + self.arVx = _arVx + arVxWasSubm = True + elif(isinstance(_arVx, list)): + self.arVx = array('d', _arVx) + arVxWasSubm = True + elif(nElem == 1): + self.arVx = array('d', [0]) + self.arVx[0] = _arVx + + arVyWasSubm = False + if(_arVy is None): + self.arVy = array('d', [0]*nElem) + elif(isinstance(_arVy, array)): + self.arVy = _arVy + arVyWasSubm = True + elif(isinstance(_arVy, list)): + self.arVy = array('d', _arVy) + arVyWasSubm = True + elif(nElem == 1): + self.arVy = array('d', [0]) + self.arVy[0] = _arVy + + if(_arVz is None): + self.arVz = array('d', [1]*nElem) + if(arVxWasSubm and arVyWasSubm): + lenArVx = len(_arVx) + lenArVy = len(_arVy) + if(lenArVx == lenArVy): + for i in range(lenArVx): + self.arVz[i] = sqrt(1. - _arVx[i]*_arVx[i] - _arVy[i]*_arVy[i]) + elif(isinstance(_arVz, array)): + self.arVz = _arVz + elif(isinstance(_arVz, list)): + self.arVz = array('d', _arVz) + elif(nElem == 1): + self.arVz = array('d', [1]) + self.arVz[0] = _arVz + + if(_arAng is None): + self.arAng = array('d', [0]*nElem) + elif(isinstance(_arAng, array)): + self.arAng = _arAng + elif(isinstance(_arAng, list)): + self.arAng = array('d', _arAng) + elif(nElem == 1): + self.arAng = array('d', [0]) + self.arAng[0] = _arAng def allocate(self, _nElem): self.arMagFld = [SRWLMagFld()]*_nElem self.arXc = array('d', [0]*_nElem) self.arYc = array('d', [0]*_nElem) self.arZc = array('d', [0]*_nElem) + self.arVx = array('d', [0]*_nElem) + self.arVy = array('d', [0]*_nElem) + self.arVz = array('d', [1]*_nElem) + self.arAng = array('d', [0]*_nElem) + + def add(self, _mag, _xc=None, _yc=None, _zc=None, _vx=None, _vy=None, _vz=None, _ang=None): + """Adds magnetic element to container + :param _mag: magnetic element (or array of elements) to be added + :param _xc: horizontal center position (or array of center positions) of magnetic field element to be added [m] + :param _yc: vertical center positions (or array of center positions) of magnetic field element to be added [m] + :param _zc: longitudinal center positions (or array of center positions) of magnetic field element to be added [m] + :param _vx: horizontal component of axis vectors of magnetic field element to be added [rad] + :param _vy: vertical component of axis vectors of magnetic field element to be added [rad] + :param _vz: longitudinal components of axis vector of magnetic field element to be added [rad] + :param _ang: rotation angle about axis [rad] + """ + if(_mag is None): + raise Exception("No magnetic field elements were supplied for adding to container") + if(isinstance(_mag, list) or isinstance(_mag, array)): + lenMag = len(_mag) + if((_xc is None) and (_yc is None) and (_zc is None) and + (_vx is None) and (_vy is None) and (_vz is None) and (_ang is None)): + for i in range(lenMag): self.add(_mag[i]) + elif((isinstance(_xc, list) or isinstance(_xc, array)) and + (isinstance(_yc, list) or isinstance(_yc, array)) and + (isinstance(_zc, list) or isinstance(_zc, array)) and + (isinstance(_vx, list) or isinstance(_vx, array)) and + (isinstance(_vy, list) or isinstance(_vy, array)) and + (isinstance(_vz, list) or isinstance(_vz, array)) and + (isinstance(_ang, list) or isinstance(_ang, array))): + lenXc = len(_xc) + lenYc = len(_yc) + lenZc = len(_zc) + lenVx = len(_vx) + lenVy = len(_vy) + lenVz = len(_vz) + lenAng = len(_ang) + if((lenXc == lenMag) and (lenYc == lenMag) and (lenZc == lenMag) and + (lenVx == lenMag) and (lenVy == lenMag) and (lenVz == lenMag) and (lenAng == lenMag)): + for i in range(lenMag): self.add(_mag[i], _xc[i], _yc[i], _zc[i], _vx[i], _vy[i], _vz[i]) + else: raise Exception("Inconsistent magnetic element positions data") + else: + self.arMagFld.append(_mag) + if(_xc is None): _xc = 0 + if(_yc is None): _yc = 0 + if(_zc is None): _zc = 0 + if(_vx is None): _vx = 0 + if(_vy is None): _vy = 0 + if(_vz is None): + _vz = 1. + if((_vx is not None) and (_vy is not None)): + _vz = sqrt(1. - _vx*_vx - _vy*_vy) + if(_ang is None): _ang = 0 + self.arXc.append(_xc) + self.arYc.append(_yc) + self.arZc.append(_zc) + self.arVx.append(_vx) + self.arVy.append(_vy) + self.arVz.append(_vz) + self.arAng.append(_ang) #**************************************************************************** class SRWLPrtTrj(object): """Charged Particle Trajectory""" - def __init__(self, _arX=None, _arXp=None, _arY=None, _arYp=None, _arZ=None, _arZp=None, _np=0, _ctStart=0, _ctEnd=0, _partInitCond=None): + def __init__(self, _arX=None, _arXp=None, _arY=None, _arYp=None, _arZ=None, _arZp=None, _arBx=None, _arBy=None, _arBz=None, _np=0, _ctStart=0, _ctEnd=0, _partInitCond=None): """ :param _arX: array of horizontal position [m] :param _arXp: array of horizontal relative velocity (trajectory angle) [rad] @@ -212,32 +588,80 @@ def __init__(self, _arX=None, _arXp=None, _arY=None, _arYp=None, _arZ=None, _arZ :param _arYp: array of vertical relative velocity (trajectory angle) [rad] :param _arZ: array of longitudinal positions [m] :param _arZp: array of longitudinal relative velocity [rad] + :param _arBx: array of horizontal magnetic field component "seen" by particle [T] + :param _arBy: array of vertical magnetic field component "seen" by particle [T] + :param _arBz: array of longitudinal magnetic field component "seen" by particle [T] :param _np: number of trajectory points :param _ctStart: start value of independent variable (c*t) for which the trajectory should be (/is) calculated (is constant step enough?) :param _ctEnd: end value of independent variable (c*t) for which the trajectory should be (/is) calculated (is constant step enough?) :param _partInitCond: particle type and initial conditions for which the trajectory should be (/is) calculated """ - self.arX = array('d') if _arX is None else _arX - self.arY = array('d') if _arY is None else _arY - self.arY = array('d') if _arZ is None else _arZ - self.arXp = array('d') if _arXp is None else _arXp - self.arYp = array('d') if _arYp is None else _arYp - self.arZp = array('d') if _arZp is None else _arZp + + if(_np > 0): + self.arX = array('d', [0]*_np) if _arX is None else _arX + self.arY = array('d', [0]*_np) if _arY is None else _arY + self.arZ = array('d', [0]*_np) if _arZ is None else _arZ + self.arXp = array('d', [0]*_np) if _arXp is None else _arXp + self.arYp = array('d', [0]*_np) if _arYp is None else _arYp + self.arZp = array('d', [0]*_np) if _arZp is None else _arZp + else: + self.arX = array('d') if _arX is None else _arX + self.arY = array('d') if _arY is None else _arY + self.arZ = array('d') if _arZ is None else _arZ + self.arXp = array('d') if _arXp is None else _arXp + self.arYp = array('d') if _arYp is None else _arYp + self.arZp = array('d') if _arZp is None else _arZp + + if _arBx is not None: self.arBx = _arBx #by default, arBx, _arBy, arBz are not created + if _arBy is not None: self.arBy = _arBy + if _arBz is not None: self.arBz = _arBz + self.np = _np self.ctStart = _ctStart self.ctEnd = _ctEnd self.partInitCond = SRWLParticle() if _partInitCond is None else _partInitCond - def allocate(self, _np): + def allocate(self, _np, _allB=False): _np = int(_np) - self.arX = array('d', [0] * _np) - self.arXp = array('d', [0] * _np) - self.arY = array('d', [0] * _np) - self.arYp = array('d', [0] * _np) - self.arZ = array('d', [0] * _np) - self.arZp = array('d', [0] * _np) + self.arX = array('d', [0]*_np) + self.arXp = array('d', [0]*_np) + self.arY = array('d', [0]*_np) + self.arYp = array('d', [0]*_np) + self.arZ = array('d', [0]*_np) + self.arZp = array('d', [0]*_np) self.np = _np + if _allB == True: + self.arBx = array('d', [0]*_np) + self.arBy = array('d', [0]*_np) + self.arBz = array('d', [0]*_np) + def save_ascii(self, _file_path): + """Auxiliary function to write tabulated Trajectory data to ASCII file""" + f = open(_file_path, 'w') + resStr = '#ct [m], X [m], BetaX [rad], Y [m], BetaY [rad], Z [m], BetaZ [rad]' + if(hasattr(self, 'arBx')): + resStr += ', Bx [T]' + if(hasattr(self, 'arBy')): + resStr += ', By [T]' + if(hasattr(self, 'arBz')): + resStr += ', Bz [T]' + f.write(resStr + '\n') + ctStep = 0 + if self.np > 0: + ctStep = (self.ctEnd - self.ctStart)/(self.np - 1) + ct = self.ctStart + for i in range(self.np): + resStr = str(ct) + '\t' + repr(self.arX[i]) + '\t' + repr(self.arXp[i]) + '\t' + repr(self.arY[i]) + '\t' + repr(self.arYp[i]) + '\t' + repr(self.arZ[i]) + '\t' + repr(self.arZp[i]) + if(hasattr(self, 'arBx')): + resStr += '\t' + repr(self.arBx[i]) + if(hasattr(self, 'arBy')): + resStr += '\t' + repr(self.arBy[i]) + if(hasattr(self, 'arBz')): + resStr += '\t' + repr(self.arBz[i]) + f.write(resStr + '\n') + ct += ctStep + f.close() + #**************************************************************************** class SRWLKickM(object): """Kick Matrix (for fast trajectory calculation)""" @@ -272,13 +696,14 @@ def __init__(self, _arKickMx=None, _arKickMy=None, _order=2, _nx=0, _ny=0, _nz=0 #**************************************************************************** class SRWLGsnBm(object): - """Gaussian Beam""" + """(Coherent) Gaussian (Radiation) Beam""" def __init__(self, _x=0, _y=0, _z=0, _xp=0, _yp=0, _avgPhotEn=1, _pulseEn=1, _repRate=1, _polar=1, _sigX=10e-06, _sigY=10e-06, _sigT=1e-15, _mx=0, _my=0): + #_sigY=10e-06, _sigT=1e-15, _mx=0, _my=0, _arIncohStatMom2=None): #OC15092017 (?) """ - :param _x: average horizontal coordinates of waist [m] - :param _y: average vertical coordinates of waist [m] + :param _x: average horizontal coordinate of waist [m] + :param _y: average vertical coordinate of waist [m] :param _z: average longitudinal coordinate of waist [m] :param _xp: average horizontal angle at waist [rad] :param _yp: average verical angle at waist [rad] @@ -307,11 +732,33 @@ def __init__(self, _x=0, _y=0, _z=0, _xp=0, _yp=0, _avgPhotEn=1, _pulseEn=1, _re self.mx = _mx self.my = _my + #if(_arIncohStatMom2 is not None): self.arIncohStatMom2 = _arIncohStatMom2 #OC15092017 (?) + +#**************************************************************************** +class SRWLPtSrc(object): + """Point Source (emitting coherent spherical wave)""" + + def __init__(self, _x=0, _y=0, _z=0, _flux=1, _unitFlux=1, _polar=1): + """ + :param _x: horizontal position [m] + :param _y: vertical position [m] + :param _z: longitudinal position [m] + :param _flux: spectral flux value + :param _unitFlux: spectral flux units: 1- ph/s/.1%bw, 2- W/eV + :param _polar: polarization 1- lin. hor., 2- lin. vert., 3- lin. 45 deg., 4- lin.135 deg., 5- circ. right, 6- circ. left, 7- radial + """ + self.x = _x + self.y = _y + self.z = _z + self.flux = _flux + self.unitFlux = _unitFlux + self.polar = _polar + #**************************************************************************** class SRWLRadMesh(object): """Radiation Mesh (Sampling)""" - def __init__(self, _eStart=0, _eFin=0, _ne=1, _xStart=0, _xFin=0, _nx=1, _yStart=0, _yFin=0, _ny=1, _zStart=0): + def __init__(self, _eStart=0, _eFin=0, _ne=1, _xStart=0, _xFin=0, _nx=1, _yStart=0, _yFin=0, _ny=1, _zStart=0, _nvx=0, _nvy=0, _nvz=1, _hvx=1, _hvy=0, _hvz=0, _arSurf=None): """ :param _eStart: initial value of photon energy (/time) :param _eFin: final value of photon energy (/time) @@ -323,6 +770,13 @@ def __init__(self, _eStart=0, _eFin=0, _ne=1, _xStart=0, _xFin=0, _nx=1, _yStart :param _yFin: final value of vertical position (/angle) :param _ny: number of points vs vertical position (/angle) :param _zStart: longitudinal position + :param _nvx: horizontal lab-frame coordinate of inner normal to observation plane (/ surface in its center) + :param _nvy: vertical lab-frame coordinate of inner normal to observation plane (/ surface in its center) + :param _nvz: longitudinal lab-frame coordinate of inner normal to observation plane (/ surface in its center) + :param _hvx: horizontal lab-frame coordinate of the horizontal base vector of the observation plane (/ surface in its center) + :param _hvy: vertical lab-frame coordinate of the horizontal base vector of the observation plane (/ surface in its center) + :param _hvz: longitudinal lab-frame coordinate of the horizontal base vector of the observation plane (/ surface in its center) + :param _arSurf: array defining the observation surface (as function of 2 variables - x & y - on the mesh given by _xStart, _xFin, _nx, _yStart, _yFin, _ny; to be used in case this surface differs from plane) """ self.eStart = _eStart self.eFin = _eFin @@ -335,21 +789,53 @@ def __init__(self, _eStart=0, _eFin=0, _ne=1, _xStart=0, _xFin=0, _nx=1, _yStart self.ny = _ny self.zStart = _zStart + self.nvx = _nvx + self.nvy = _nvy + self.nvz = _nvz + self.hvx = _hvx + self.hvy = _hvy + self.hvz = _hvz + self.arSurf = _arSurf + def set_from_other(self, _mesh): - self.eStart = _mesh.eStart; self.eFin = _mesh.eFin; self.ne = _mesh.ne; - self.xStart = _mesh.xStart; self.xFin = _mesh.xFin; self.nx = _mesh.nx; + self.eStart = _mesh.eStart; self.eFin = _mesh.eFin; self.ne = _mesh.ne; + self.xStart = _mesh.xStart; self.xFin = _mesh.xFin; self.nx = _mesh.nx; self.yStart = _mesh.yStart; self.yFin = _mesh.yFin; self.ny = _mesh.ny; self.zStart = _mesh.zStart + self.nvx = _mesh.nvx; self.nvy = _mesh.nvy; self.nvz = _mesh.nvz + self.hvx = _mesh.hvx; self.hvy = _mesh.hvy; self.hvz = _mesh.hvz + del self.arSurf; self.arSurf = None + if(_mesh.arSurf is not None): + try: + lenArSurf = len(_mesh.arSurf) + if(lenArSurf > 0): + self.arSurf = array('d', [0]*lenArSurf) + for i in range(lenArSurf): + self.arSurf[i] = _mesh.arSurf[i] + except: + pass + + def get_dep_type(self): #Get possible dependency type (for intensity calc.) + depType = -1 + if((self.ne >= 1) and (self.nx == 1) and (self.ny == 1)): depType = 0 + elif((self.ne == 1) and (self.nx > 1) and (self.ny == 1)): depType = 1 + elif((self.ne == 1) and (self.nx == 1) and (self.ny > 1)): depType = 2 + elif((self.ne == 1) and (self.nx > 1) and (self.ny > 1)): depType = 3 + elif((self.ne > 1) and (self.nx > 1) and (self.ny == 1)): depType = 4 + elif((self.ne > 1) and (self.nx == 1) and (self.ny > 1)): depType = 5 + elif((self.ne > 1) and (self.nx > 1) and (self.ny > 1)): depType = 6 + return depType + #**************************************************************************** class SRWLStokes(object): """Radiation Stokes Parameters""" #def __init__(self, _arS0=None, _arS1=None, _arS2=None, _arS3=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStart=0, _xFin=0, _nx=0, _yStart=0, _yFin=0, _ny=0): - def __init__(self, _arS=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStart=0, _xFin=0, _nx=0, _yStart=0, _yFin=0, _ny=0): + def __init__(self, _arS=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStart=0, _xFin=0, _nx=0, _yStart=0, _yFin=0, _ny=0, _mutual=0): """ :param _arS: flat C-aligned array of all Stokes components (outmost loop over Stokes parameter number); NOTE: only 'f' (float) is supported for the moment (Jan. 2012) - :param _typeStokes: electric field numerical type: 'f' (float) or 'd' (double, not supported yet) + :param _typeStokes: numerical type: 'f' (float) or 'd' (double, not supported yet) :param _eStart: initial value of photon energy (/time) :param _eFin: final value of photon energy (/time) :param _ne: numbers of points vs photon energy @@ -359,6 +845,7 @@ def __init__(self, _arS=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStar :param _yStart: initial value of vertical position :param _yFin: final value of vertical position :param _ny: numbers of points vs vertical position + :param _mutual: mutual Stokes components (4*(_ne*_nx*_ny_)^2 values) """ self.arS = _arS #flat C-aligned array of all Stokes components (outmost loop over Stokes parameter number); NOTE: only 'f' (float) is supported for the moment (Jan. 2012) self.numTypeStokes = _typeStokes #electric field numerical type: 'f' (float) or 'd' (double) @@ -366,11 +853,12 @@ def __init__(self, _arS=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStar self.avgPhotEn = 0 #average photon energy for time-domain simulations self.presCA = 0 #presentation/domain: 0- coordinates, 1- angles self.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time - self.unitStokes = 1 #electric field units: 0- arbitrary, 1- Phot/s/0.1%bw/mm^2 ? + self.unitStokes = 1 #Stokes units: 0- arbitrary, 1- Phot/s/0.1%bw/mm^2 ? + self.mutual = _mutual #indicator of Mutual Stokes components nProd = _ne*_nx*_ny #array length to store one component of complex electric field if((_arS == 1) and (nProd > 0)): - self.allocate(_ne, _nx, _ny, _typeStokes) + self.allocate(_ne, _nx, _ny, _typeStokes, _mutual) #s0needed = 0 #s1needed = 0 #s2needed = 0 @@ -386,9 +874,8 @@ def __init__(self, _arS=None, _typeStokes='f', _eStart=0, _eFin=0, _ne=0, _xStar #if((s0needed > 0) or (s1needed > 0) or (s2needed > 0) or (s3needed > 0)): # self.allocate(_ne, _nx, _ny, s0needed, s1needed, s2needed, s3needed) - #def allocate(self, _ne, _nx, _ny, s0needed=1, s1needed=1, s2needed=1, s3needed=1, _typeStokes='f'): - def allocate(self, _ne, _nx, _ny, _typeStokes='f'): + def allocate(self, _ne, _nx, _ny, _typeStokes='f', _mutual=0): #print('') #debugging #print(' (re-)allocating: old point numbers: ne=',self.mesh.ne,' nx=',self.mesh.nx,' ny=',self.mesh.ny,' type:',self.numTypeStokes) #print(' new point numbers: ne=',_ne,' nx=',_nx,' ny=',_ny,' type:',_typeStokes) @@ -405,30 +892,108 @@ def allocate(self, _ne, _nx, _ny, _typeStokes='f'): #if s3needed: # del self.arS3 # self.arS3 = array(_typeStokes, [0]*nTot) - nTot = _ne*_nx*_ny*4 #array length of all Stokes components + + nTot = _ne*_nx*_ny + if _mutual > 0: + #nTot *= nTot + nTot *= (nTot*2) #OC04052018 (since may be a complex entity) + nTot *= 4 #array length of all Stokes components + #eventually allow for storage of less than 4 Stokes components! + + #DEBUG + #print('_ne=', _ne, '_nx=', _nx, '_ny=', _ny, 'nTot=', nTot) + #END DEBUG + self.arS = array(_typeStokes, [0]*nTot) self.numTypeStokes = _typeStokes self.mesh.ne = _ne self.mesh.nx = _nx self.mesh.ny = _ny + self.mutual = _mutual - def avg_update_same_mesh(self, _more_stokes, _iter, _n_stokes_comp=4): + def add_stokes(self, _st, _n_comp=4, _mult=1, _meth=0): + """Add Another Stokes structure + :param _st: Stokes structure to be added + :param _n_comp: number of components to treat + :param _mult: multiplier + :param _meth: method of adding the Stokes structure _st: + 0- simple addition assuming _wfr to have same mesh as this wavefront + 1- add using bilinear interpolation (taking into account meshes of the two wavefronts) + 2- add using bi-quadratic interpolation (taking into account meshes of the two wavefronts) + 3- add using bi-cubic interpolation (taking into account meshes of the two wavefronts) + """ + + #nTot = _n_comp*self.mesh.ne*self.mesh.nx*self.mesh.ny #eventually allow for storage of less than 4 Stokes components! + nTot = self.mesh.ne*self.mesh.nx*self.mesh.ny + if(self.mutual > 0): + #nTot *= nTot + nTot *= (nTot*2) #OC04052018 (since may be a complex entity) + + nTot *= _n_comp #eventually allow for storage of less than 4 Stokes components! + + if(_meth == 0): + if((self.mesh.ne != _st.mesh.ne) or (self.mesh.nx != _st.mesh.nx) or (self.mesh.ny != _st.mesh.ny)): + raise Exception("Stokes parameters addition can not be performed by this method because of unequal sizes of the two Stokes structures") + + st_arS = _st.arS + if(_mult == 1): + for i in range(nTot): + #for some reason, this increases memory requirements in Py(?): + self.arS[i] += st_arS[i] + else: + for i in range(nTot): + #for some reason, this increases memory requirements in Py(?): + self.arS[i] += _mult*st_arS[i] + + elif(_meth == 1): + #to implement + raise Exception("This Stokes parameters addition method is not implemented yet") + + elif(_meth == 2): + #to implement + raise Exception("This Stokes parameters addition method is not implemented yet") + + elif(_meth == 3): + #to implement + raise Exception("This Stokes parameters addition method is not implemented yet") + + def avg_update_same_mesh(self, _more_stokes, _iter, _n_stokes_comp=4, _mult=1.): """ Update this Stokes data structure with new data, contained in the _more_stokes structure, calculated on the same mesh, so that this structure would represent estimation of average of (_iter + 1) structures :param _more_stokes: Stokes data structure to "add" to the estimation of average :param _iter: number of Stokes structures already "added" previously :param _n_stokes_comp: number of Stokes components to treat (1 to 4) + :param _mult: optional multiplier of the _more_stokes """ - nStPt = self.mesh.ne*self.mesh.nx*self.mesh.ny*_n_stokes_comp - for ir in range(nStPt): - self.arS[ir] = (self.arS[ir]*_iter + _more_stokes.arS[ir])/(_iter + 1) - def avg_update_interp(self, _more_stokes, _iter, _ord, _n_stokes_comp=4): + #DEBUG + #print('avg_update_same_mesh: iter=', _iter, _mult) + + #nStPt = self.mesh.ne*self.mesh.nx*self.mesh.ny*_n_stokes_comp + nStPt = self.mesh.ne*self.mesh.nx*self.mesh.ny + if self.mutual > 0: + #nStPt *= nStPt + nStPt *= (nStPt*2) #OC04052018 (since may be a complex entity) + + nStPt *= _n_stokes_comp + if(_mult == 1.): + for ir in range(nStPt): + self.arS[ir] = (self.arS[ir]*_iter + _more_stokes.arS[ir])/(_iter + 1) + else: + for ir in range(nStPt): + self.arS[ir] = (self.arS[ir]*_iter + _mult*_more_stokes.arS[ir])/(_iter + 1) + + def avg_update_interp(self, _more_stokes, _iter, _ord, _n_stokes_comp=4, _mult=1.): """ Update this Stokes data structure with new data, contained in the _more_stokes structure, calculated on a different 2D mesh, so that it would represent estimation of average of (_iter + 1) structures :param _more_stokes: Stokes data structure to "add" to the estimation of average :param _iter: number of Stokes structures already "added" previously :param _ord: order of 2D interpolation to use (1- bilinear, ..., 3- bi-cubic) :param _n_stokes_comp: number of Stokes components to treat (1 to 4) + :param _mult: optional multiplier of the _more_stokes """ + + #DEBUG + #print('avg_update_interp: iter=', _iter, _mult) + eNpMeshRes = self.mesh.ne xNpMeshRes = self.mesh.nx xStartMeshRes = self.mesh.xStart @@ -496,6 +1061,16 @@ def avg_update_interp(self, _more_stokes, _iter, _ord, _n_stokes_comp=4): a11 = a00 - f01 - f10 + f11 fInterp = a00 + tx*(a10 + ty*a11) + ty*a01 + #DEBUG + #if(isnan(fInterp)): + # print('nx=', _more_stokes.mesh.nx, ' ny=', _more_stokes.mesh.ny) + # print('i00=', iy0_nx_ix_per + ix0_ix_per_p_ix_ofst, ' i10=', iy0_nx_ix_per + ix1_ix_per_p_ix_ofst, ' i01=', iy1_nx_ix_per + ix0_ix_per_p_ix_ofst, ' i11=', iy1_nx_ix_per + ix1_ix_per_p_ix_ofst) + # print('ix0=', ix0, ' ix1=', ix1, ' iy0=', iy0, ' iy1=', iy1) + # print('f00=', a00, ' f10=', f10, ' f01=', f01, ' f11=', f11) + # sys.exit() + #else: print('OK') + #END DEBUG + elif(_ord == 2): #bi-quadratic interpolation based on 6 points ix0 = int(round((xMeshRes - xStartWfr)/xStepWfr)) if((ix0 < 0) or (ix0 >= xNpWfr - 1)): @@ -588,579 +1163,3795 @@ def avg_update_interp(self, _more_stokes, _iter, _ord, _n_stokes_comp=4): a13 = 0.5*(f10 - f11 - a00 + f01) + (f0m1 + f12 - f02 - f1m1)/6 fInterp = a00 + tx*(a10 + tx*(a20 + tx*(a30 + ty*a31) + ty*a21) + ty*a11) + ty*(a01 + ty*(a02 + ty*(a03 + tx*a13) + tx*a12)) - self.arS[ir] = (self.arS[ir]*_iter + fInterp)/(_iter + 1) + #self.arS[ir] = (self.arS[ir]*_iter + fInterp)/(_iter + 1) + self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/(_iter + 1) + ir += 1 iOfstSt += nRadWfr -#**************************************************************************** -class SRWLWfr(object): - """Radiation Wavefront (Electric Field)""" - #arEx = 0 #array('f', [0]*2) #horizontal complex electric field component array; NOTE: only 'f' (float) is supported for the moment (Jan. 2011) - #arEy = 0 #array('f', [0]*2) #vertical complex electric field component array - #mesh = SRWLRadMesh() - ##eStart = 0 #initial and final values of photon energy (/time), horizontal and vertical positions - ##eFin = 0 - ##xStart = 0 - ##xFin = 0 - ##yStart = 0 - ##yFin = 0 - ##zStart = 0 - ##ne = 0 #numbers of points vs photon energy, horizontal and vertical positions - ##nx = 0 - ##ny = 0 - #Rx = 0 #instant wavefront radii - #Ry = 0 - #dRx = 0 #error of wavefront radii - #dRy = 0 - #xc = 0 #instant transverse coordinates of wavefront instant "source center" - #yc = 0 - #avgPhotEn = 0 #average photon energy for time-domain simulations - #presCA = 0 #presentation/domain: 0- coordinates, 1- angles - #presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time - #numTypeElFld = 'f' #electric field numerical type: 'f' (float) or 'd' (double) - #unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2) ? - #partBeam = SRWLPartBeam() #particle beam source; strictly speaking, it should be just SRWLParticle; however, "multi-electron" information can appear useful for those cases when "multi-electron intensity" can be deduced from the "single-electron" one by convolution - #arElecPropMatr = array('d', [0]*20) #effective 1st order "propagation matrix" for electron beam parameters - #arMomX = array('d', [0]*11) #statistical moments (of Wigner distribution); to check the exact number of moments required - #arMomY = array('d', [0]*11) - #arWfrAuxData = array('d', [0]*30) #array of auxiliary wavefront data - - def __init__(self, _arEx=None, _arEy=None, _typeE='f', _eStart=0, _eFin=0, _ne=0, _xStart=0, _xFin=0, _nx=0, _yStart=0, _yFin=0, _ny=0, _zStart=0, _partBeam=None): - """ - :param _arEx: horizontal complex electric field component array; NOTE: only 'f' (float) is supported for the moment (Jan. 2011) - :param _arEy: vertical complex electric field component array - :param _typeE: electric field numerical type: 'f' (float) or 'd' (double) - :param _eStart: initial value of photon energy (/time) - :param _eFin: final value of photon energy (/time) - :param _ne: numbers of points vs photon energy - :param _xStart: initial value of horizontal positions - :param _xFin: final value of horizontal positions - :param _nx: numbers of points vs horizontal positions - :param _yStart: initial vertical positions - :param _yFin: final value of vertical positions - :param _ny: numbers of points vs vertical positions - :param _zStart: longitudinal position - :param _partBeam: particle beam source; strictly speaking, it should be just SRWLParticle; however, "multi-electron" information can appear useful for those cases when "multi-electron intensity" can be deduced from the "single-electron" one by convolution - - Some additional parameters, that are not included in constructor arguments: - Rx, Ry: instant wavefront radii - dRx, dRy: error of wavefront radii - xc, yc: transverse coordinates of wavefront instant "source center" - avgPhotEn: average photon energy for time-domain simulations - presCA: presentation/domain: 0- coordinates, 1- angles - presFT: presentation/domain: 0- frequency (photon energy), 1- time - unitElFld: electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2) - arElecPropMatr: effective 1st order "propagation matrix" for electron beam parameters - arMomX, arMomY: statistical moments (of Wigner distribution); to check the exact number of moments required - arWfrAuxData: array of auxiliary wavefront data + def avg_update_interp_mutual(self, _more_stokes, _iter, _n_stokes_comp=4, _mult=1.): + """ Update this Stokes data structure with new data, contained in the _more_stokes structure, calculated on a different 2D mesh, so that it would represent estimation of average of (_iter + 1) structures + :param _more_stokes: Stokes data structure to "add" to the estimation of average + :param _iter: number of Stokes structures already "added" previously + :param _n_stokes_comp: number of Stokes components to treat (1 to 4) + :param _mult: optional multiplier of the _more_stokes """ - self.arEx = _arEx - self.arEy = _arEy - #self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _xStart, _xFin, _nx, _yStart, _yFin, _ny) - self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _xStart, _xFin, _nx, _yStart, _yFin, _ny, _zStart) - self.numTypeElFld = _typeE - self.partBeam = SRWLPartBeam() if _partBeam is None else _partBeam + eNpMeshRes = self.mesh.ne + eStartMeshRes = self.mesh.eStart + eStepMeshRes = 0 + if(eNpMeshRes > 1): + eStepMeshRes = (self.mesh.eFin - eStartMeshRes)/(eNpMeshRes - 1) + + xNpMeshRes = self.mesh.nx + xStartMeshRes = self.mesh.xStart + xStepMeshRes = 0 + if(xNpMeshRes > 1): + xStepMeshRes = (self.mesh.xFin - xStartMeshRes)/(xNpMeshRes - 1) + + yNpMeshRes = self.mesh.ny + yStartMeshRes = self.mesh.yStart + yStepMeshRes = 0 + if(yNpMeshRes > 1): + yStepMeshRes = (self.mesh.yFin - yStartMeshRes)/(yNpMeshRes - 1) - self.Rx = 0 #instant wavefront radii - self.Ry = 0 - self.dRx = 0 #error of wavefront radii - self.dRy = 0 - self.xc = 0 #instant transverse coordinates of wavefront instant "source center" - self.yc = 0 - self.avgPhotEn = 0 #average photon energy for time-domain simulations - self.presCA = 0 #presentation/domain: 0- coordinates, 1- angles - self.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time - self.unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2) ? - self.arElecPropMatr = array('d', [0] * 20) #effective 1st order "propagation matrix" for electron beam parameters - self.arMomX = array('d', [0] * 11 * _ne) #statistical moments (of Wigner distribution); to check the exact number of moments required - self.arMomY = array('d', [0] * 11 * _ne) - self.arWfrAuxData = array('d', [0] * 30) #array of auxiliary wavefront data + eNpWfr = _more_stokes.mesh.ne + eStartWfr = _more_stokes.mesh.eStart + eNpWfr = _more_stokes.mesh.ne + eStepWfr = 0 + if(eNpWfr > 1): + eStepWfr = (_more_stokes.mesh.eFin - eStartWfr)/(eNpWfr - 1) + eNpWfr_mi_1 = eNpWfr - 1 + + xStartWfr = _more_stokes.mesh.xStart + xNpWfr = _more_stokes.mesh.nx + xStepWfr = 0 + if(xNpWfr > 1): + xStepWfr = (_more_stokes.mesh.xFin - xStartWfr)/(xNpWfr - 1) + xNpWfr_mi_1 = xNpWfr - 1 - nProd = _ne * _nx * _ny #array length to store one component of complex electric field - EXNeeded = 0 - EYNeeded = 0 - if(_arEx == 1) and (nProd > 0): - EXNeeded = 1 - if(_arEy == 1) and (nProd > 0): - EYNeeded = 1 - if(EXNeeded > 0) or (EYNeeded > 0): - self.allocate(_ne, _nx, _ny, EXNeeded, EYNeeded) + yStartWfr = _more_stokes.mesh.yStart + yNpWfr = _more_stokes.mesh.ny + yStepWfr = 0 + if(yNpWfr > 1): + yStepWfr = (_more_stokes.mesh.yFin - yStartWfr)/(yNpWfr - 1) + yNpWfr_mi_1 = yNpWfr - 1 - def allocate(self, _ne, _nx, _ny, EXNeeded=1, EYNeeded=1, typeE='f'): - #print('') #debugging - #print(' (re-)allocating: old point numbers: ne=',self.mesh.ne,' nx=',self.mesh.nx,' ny=',self.mesh.ny) #,' type:',self.numTypeElFld) - #print(' new point numbers: ne=',_ne,' nx=',_nx,' ny=',_ny) #,' type:',typeE) - nTot = 2*_ne*_nx*_ny #array length to store one component of complex electric field - nMom = 11*_ne - if EXNeeded: - #print(' trying to (re-)allocate Ex ... ', end='') - del self.arEx - self.arEx = array(typeE, [0]*nTot) - #print('done') - if len(self.arMomX) != nMom: - del self.arMomX - self.arMomX = array('d', [0]*nMom) - if EYNeeded: - #print(' trying to (re-)allocate Ey ... ', end='') - #del self.arEy - self.arEy = array(typeE, [0]*nTot) - #print('done') - if len(self.arMomY) != nMom: - del self.arMomY - self.arMomY = array('d', [0]*nMom) - self.numTypeElFld = typeE - self.mesh.ne = _ne - self.mesh.nx = _nx - self.mesh.ny = _ny + #nRadWfr = eNpWfr*xNpWfr*yNpWfr + #nRadWfr *= nRadWfr - def calc_stokes(self, _stokes): - """Calculate Stokes parameters from Electric Field""" - nTot = self.mesh.ne*self.mesh.nx*self.mesh.ny - #if(type(_stokes).__name__ != 'SRWLStokes')): - if(isinstance(_stokes, SRWLStokes) == False): - raise Exception("Incorrect Stokes parameters object submitted") - nTotSt = nTot*4 - nTot2 = nTot*2 - nTot3 = nTot*3 - if(_stokes.arS != None): - if(len(_stokes.arS) < nTotSt): - _stokes.arS = array('f', [0]*nTotSt) - else: - _stokes.arS = array('f', [0]*nTotSt) - for i in range(nTot): - i2 = i*2 - i2p1 = i2 + 1 - reEx = self.arEx[i2] - imEx = self.arEx[i2p1] - reEy = self.arEy[i2] - imEy = self.arEy[i2p1] - intLinX = reEx*reEx + imEx*imEx - intLinY = reEy*reEy + imEy*imEy - _stokes.arS[i] = intLinX + intLinY - _stokes.arS[i + nTot] = intLinX - intLinY #check sign - _stokes.arS[i + nTot2] = -2*(reEx*reEy + imEx*imEy) #check sign - _stokes.arS[i + nTot3] = 2*(-reEx*reEy + imEx*imEy) #check sign - _stokes.mesh.set_from_other(self.mesh) + perEp = 2 #OC04052018 (since may be a complex entity) + perE = perEp*eNpWfr #OC04052018 + #perE = eNpWfr + perXp = perE*eNpWfr + perX = perXp*xNpWfr + perYp = perX*xNpWfr + perY = perYp*yNpWfr + nRadWfr = perY*yNpWfr -#**************************************************************************** -class SRWLOpt(object): - """Optical Element (base class)""" + iter_p_1 = _iter + 1 #OC04052018 + iter_d_iter_p_1 = _iter/iter_p_1 -class SRWLOptD(SRWLOpt): - """Optical Element: Drift Space""" - - def __init__(self, _L=0): - """ - :param _L: Length [m] - """ - self.L = _L + iOfstSt = 0 + ir = 0 + for iSt in range(_n_stokes_comp): + for iy in range(yNpMeshRes): + doZeroFy = False + yMeshRes = yStartMeshRes + iy*yStepMeshRes + iy0 = 0 + if(yStepWfr > 0): iy0 = int(trunc((yMeshRes - yStartWfr)/yStepWfr + 1.e-09)) + if((iy0 < 0) or (iy0 > yNpWfr_mi_1)): + doZeroFy = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + iy1 = iy0 + 1 + if(iy1 > yNpWfr_mi_1): iy1 = yNpWfr_mi_1 + ty = 0 + if(yStepWfr > 0): ty = (yMeshRes - (yStartWfr + yStepWfr*iy0))/yStepWfr -class SRWLOptA(SRWLOpt): - """Optical Element: Aperture / Obstacle""" - - def __init__(self, _shape='r', _ap_or_ob='a', _Dx=0, _Dy=0, _x=0, _y=0): - """ - :param _shape: 'r' for rectangular, 'c' for circular + iy0_perY = iy0*perY + iy1_perY = iy1*perY + + for iyp in range(yNpMeshRes): + doZeroFyp = False + ypMeshRes = yStartMeshRes + iyp*yStepMeshRes + iyp0 = 0 + if(yStepWfr > 0): iyp0 = int(trunc((ypMeshRes - yStartWfr)/yStepWfr + 1.e-09)) + if((iyp0 < 0) or (iyp0 > yNpWfr_mi_1)): + doZeroFyp = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + iyp1 = iyp0 + 1 + if(iyp1 > yNpWfr_mi_1): iyp1 = yNpWfr_mi_1 + typ = 0 + if(yStepWfr > 0): typ = (ypMeshRes - (yStartWfr + yStepWfr*iyp0))/yStepWfr + + iyp0_perYp = iyp0*perYp + iyp1_perYp = iyp1*perYp + iyp0_perYp_p_iy0_perY = iyp0_perYp + iy0_perY + iyp1_perYp_p_iy0_perY = iyp1_perYp + iy0_perY + iyp0_perYp_p_iy1_perY = iyp0_perYp + iy1_perY + iyp1_perYp_p_iy1_perY = iyp1_perYp + iy1_perY + + for ix in range(xNpMeshRes): + doZeroFx = False + xMeshRes = xStartMeshRes + ix*xStepMeshRes + ix0 = 0 + if(xStepWfr > 0): ix0 = int(trunc((xMeshRes - xStartWfr)/xStepWfr + 1.e-09)) + if((ix0 < 0) or (ix0 > xNpWfr_mi_1)): + doZeroFx = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + ix1 = ix0 + 1 + if(ix1 > xNpWfr_mi_1): ix1 = xNpWfr_mi_1 + tx = 0 + if(xStepWfr > 0): tx = (xMeshRes - (xStartWfr + xStepWfr*ix0))/xStepWfr + + ix0_perX = ix0*perX + ix1_perX = ix1*perX + + for ixp in range(xNpMeshRes): + doZeroFxp = False + xpMeshRes = xStartMeshRes + ixp*xStepMeshRes + ixp0 = 0 + if(xStepWfr > 0): ixp0 = int(trunc((xpMeshRes - xStartWfr)/xStepWfr + 1.e-09)) + if((ixp0 < 0) or (ixp0 > xNpWfr_mi_1)): + doZeroFxp = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + ixp1 = ixp0 + 1 + if(ixp1 > xNpWfr_mi_1): ixp1 = xNpWfr_mi_1 + txp = 0 + if(xStepWfr > 0): txp = (xpMeshRes - (xStartWfr + xStepWfr*ixp0))/xStepWfr + + ixp0_perXp = ixp0*perXp + ixp1_perXp = ixp1*perXp + + ixp0_perXp_p_ix0_perX = ixp0_perXp + ix0_perX + ixp1_perXp_p_ix0_perX = ixp1_perXp + ix0_perX + ixp0_perXp_p_ix1_perX = ixp0_perXp + ix1_perX + ixp1_perXp_p_ix1_perX = ixp1_perXp + ix1_perX + + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY = ixp0_perXp_p_ix0_perX + iyp0_perYp_p_iy0_perY + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY = ixp1_perXp_p_ix0_perX + iyp0_perYp_p_iy0_perY + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY = ixp0_perXp_p_ix1_perX + iyp0_perYp_p_iy0_perY + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY = ixp0_perXp_p_ix0_perX + iyp1_perYp_p_iy0_perY + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY = ixp0_perXp_p_ix0_perX + iyp0_perYp_p_iy1_perY + + ixp1_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY = ixp1_perXp_p_ix1_perX + iyp0_perYp_p_iy0_perY + ixp1_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY = ixp1_perXp_p_ix0_perX + iyp1_perYp_p_iy0_perY + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY = ixp1_perXp_p_ix0_perX + iyp0_perYp_p_iy1_perY + ixp0_perXp_p_ix1_perX_p_iyp1_perYp_p_iy0_perY = ixp0_perXp_p_ix1_perX + iyp1_perYp_p_iy0_perY + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy1_perY = ixp0_perXp_p_ix1_perX + iyp0_perYp_p_iy1_perY + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy1_perY = ixp0_perXp_p_ix0_perX + iyp1_perYp_p_iy1_perY + + for ie in range(eNpMeshRes): + doZeroFe = False + eMeshRes = eStartMeshRes + ie*eStepMeshRes + ie0 = 0 + if(eStepWfr > 0): ie0 = int(trunc((eMeshRes - eStartWfr)/eStepWfr + 1.e-09)) + if((ie0 < 0) or (ie0 > eNpWfr_mi_1)): + doZeroFe = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + ie1 = ie0 + 1 + if(ie1 > eNpWfr_mi_1): ie1 = eNpWfr_mi_1 + te = 0 + if(eStepWfr > 0): te = (eMeshRes - (eStartWfr + eStepWfr*ie0))/eStepWfr + + ie0_perE = ie0*perE + ie1_perE = ie1*perE + + for iep in range(eNpMeshRes): + doZeroFep = False + epMeshRes = eStartMeshRes + iep*eStepMeshRes + iep0 = 0 + if(eStepWfr > 0): iep0 = int(trunc((epMeshRes - eStartWfr)/eStepWfr + 1.e-09)) + if((iep0 < 0) or (iep0 > eNpWfr_mi_1)): + doZeroFep = True + #self.arS[ir] = self.arS[ir]*_iter/(_iter + 1); ir += 1 + #continue + iep1 = iep0 + 1 + if(iep1 > eNpWfr_mi_1): iep1 = eNpWfr_mi_1 + tep = 0 + if(eStepWfr > 0): tep = (epMeshRes - (eStartWfr + eStepWfr*iep0))/eStepWfr + + iep0_perEp = iep0*perEp #OC04052018 (since may be a complex entity) + iep1_perEp = iep1*perEp + + fInterp = 0 + if(not(doZeroFy or doZeroFyp or doZeroFx or doZeroFxp or doZeroFe or doZeroFep)): + + iep0_perEp_p_ie0_perE = iep0_perEp + ie0_perE #OC04052018 + iep1_perEp_p_ie0_perE = iep1_perEp + ie0_perE + iep0_perEp_p_ie1_perE = iep0_perEp + ie1_perE + iep1_perEp_p_ie1_perE = iep1_perEp + ie1_perE + + ofst000000 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY #OC04052018 + ofst100000 = iOfstSt + iep1_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst010000 = iOfstSt + iep0_perEp_p_ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst001000 = iOfstSt + iep0_perEp_p_ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst000100 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY + ofst000010 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY + ofst000001 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY + + ofst110000 = iOfstSt + iep1_perEp_p_ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst101000 = iOfstSt + iep1_perEp_p_ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst100100 = iOfstSt + iep1_perEp_p_ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY + ofst100010 = iOfstSt + iep1_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY + ofst100001 = iOfstSt + iep1_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY + + ofst011000 = iOfstSt + iep0_perEp_p_ie1_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY + ofst010100 = iOfstSt + iep0_perEp_p_ie1_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY + ofst010010 = iOfstSt + iep0_perEp_p_ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY + ofst010001 = iOfstSt + iep0_perEp_p_ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY + + ofst001100 = iOfstSt + iep0_perEp_p_ie0_perE + ixp1_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY + ofst001010 = iOfstSt + iep0_perEp_p_ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY + ofst001001 = iOfstSt + iep0_perEp_p_ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY + + ofst000110 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp1_perYp_p_iy0_perY + ofst000101 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy1_perY + + ofst000011 = iOfstSt + iep0_perEp_p_ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy1_perY + + #a000000 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f100000 = _more_stokes.arS[iOfstSt + iep1 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f010000 = _more_stokes.arS[iOfstSt + iep0 + ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f001000 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f000100 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY] + #f000010 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY] + #f000001 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY] + + #f110000 = _more_stokes.arS[iOfstSt + iep1 + ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f101000 = _more_stokes.arS[iOfstSt + iep1 + ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f100100 = _more_stokes.arS[iOfstSt + iep1 + ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY] + #f100010 = _more_stokes.arS[iOfstSt + iep1 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY] + #f100001 = _more_stokes.arS[iOfstSt + iep1 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY] + + #f011000 = _more_stokes.arS[iOfstSt + iep0 + ie1_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy0_perY] + #f010100 = _more_stokes.arS[iOfstSt + iep0 + ie1_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY] + #f010010 = _more_stokes.arS[iOfstSt + iep0 + ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY] + #f010001 = _more_stokes.arS[iOfstSt + iep0 + ie1_perE + ixp0_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY] + + #f001100 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp1_perXp_p_ix1_perX_p_iyp0_perYp_p_iy0_perY] + #f001010 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp1_perYp_p_iy0_perY] + #f001001 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp1_perXp_p_ix0_perX_p_iyp0_perYp_p_iy1_perY] + + #f000110 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp1_perYp_p_iy0_perY] + #f000101 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix1_perX_p_iyp0_perYp_p_iy1_perY] + + #f000011 = _more_stokes.arS[iOfstSt + iep0 + ie0_perE + ixp0_perXp_p_ix0_perX_p_iyp1_perYp_p_iy1_perY] + + for ii in range(2): #OC04052018 (since may be a complex entity) + + a000000 = _more_stokes.arS[ofst000000]; ofst000000 += 1 + f100000 = _more_stokes.arS[ofst100000]; ofst100000 += 1 + f010000 = _more_stokes.arS[ofst010000]; ofst010000 += 1 + f001000 = _more_stokes.arS[ofst001000]; ofst001000 += 1 + f000100 = _more_stokes.arS[ofst000100]; ofst000100 += 1 + f000010 = _more_stokes.arS[ofst000010]; ofst000010 += 1 + f000001 = _more_stokes.arS[ofst000001]; ofst000001 += 1 + + f110000 = _more_stokes.arS[ofst110000]; ofst110000 += 1 + f101000 = _more_stokes.arS[ofst101000]; ofst101000 += 1 + f100100 = _more_stokes.arS[ofst100100]; ofst100100 += 1 + f100010 = _more_stokes.arS[ofst100010]; ofst100010 += 1 + f100001 = _more_stokes.arS[ofst100001]; ofst100001 += 1 + + f011000 = _more_stokes.arS[ofst011000]; ofst011000 += 1 + f010100 = _more_stokes.arS[ofst010100]; ofst010100 += 1 + f010010 = _more_stokes.arS[ofst010010]; ofst010010 += 1 + f010001 = _more_stokes.arS[ofst010001]; ofst010001 += 1 + + f001100 = _more_stokes.arS[ofst001100]; ofst001100 += 1 + f001010 = _more_stokes.arS[ofst001010]; ofst001010 += 1 + f001001 = _more_stokes.arS[ofst001001]; ofst001001 += 1 + + f000110 = _more_stokes.arS[ofst000110]; ofst000110 += 1 + f000101 = _more_stokes.arS[ofst000101]; ofst000101 += 1 + + f000011 = _more_stokes.arS[ofst000011]; ofst000011 += 1 + + a100000 = f100000 - a000000 + a010000 = f010000 - a000000 + a001000 = f001000 - a000000 + a000100 = f000100 - a000000 + a000010 = f000010 - a000000 + a000001 = f000001 - a000000 + a110000 = a000000 - f010000 - f100000 + f110000 + a101000 = a000000 - f001000 - f100000 + f101000 + a100100 = a000000 - f000100 - f100000 + f100100 + a100010 = a000000 - f000010 - f100000 + f100010 + a100001 = a000000 - f000001 - f100000 + f100001 + a011000 = a000000 - f001000 - f010000 + f011000 + a010100 = a000000 - f000100 - f010000 + f010100 + a010010 = a000000 - f000010 - f010000 + f010010 + a010001 = a000000 - f000001 - f010000 + f010001 + a001100 = a000000 - f000100 - f001000 + f001100 + a001010 = a000000 - f000010 - f001000 + f001010 + a001001 = a000000 - f000001 - f001000 + f001001 + a000110 = a000000 - f000010 - f000100 + f000110 + a000101 = a000000 - f000001 - f000100 + f000101 + a000011 = a000000 - f000001 - f000010 + f000011 + + fInterp = (a100000 + a110000*te + a101000*txp + a100100*tx + a100010*typ + a100001*ty)*tep + fInterp += (a010000 + a011000*txp + a010100*tx + a010010*typ + a010001*ty)*te + fInterp += (a001000 + a001100*tx + a001010*typ + a001001*ty)*txp + fInterp += (a000100 + a000110*typ + a000101*ty)*tx + (a000010 + a000011*ty)*typ + a000001*ty + a000000 + + #self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/(_iter + 1) + self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/iter_p_1 + ir += 1 + else: #OC04052018 + #self.arS[ir] = self.arS[ir]*iter_d_iter_p_1; ir += 1 + #self.arS[ir] = self.arS[ir]*iter_d_iter_p_1 + self.arS[ir] *= iter_d_iter_p_1; ir += 1 + self.arS[ir] *= iter_d_iter_p_1; ir += 1 + + #OC04052018 (commented-out) + #self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/(_iter + 1) + #ir += 1 + iOfstSt += nRadWfr + + def to_int(self, _pol=6): + """Calculates / "extracts" intensity at a given polarization from the Stokes components + :param _pol: polarization component to extract: + 0- Linear Horizontal; + 1- Linear Vertical; + 2- Linear 45 degrees; + 3- Linear 135 degrees; + 4- Circular Right; + 5- Circular Left; + 6- Total + :return: 1D array with (C-aligned) resulting intensity data + """ + + resArI = None + if(self.mutual == 0): + nPer = self.mesh.ne*self.mesh.nx*self.mesh.ny + resArI = array(self.numTypeStokes, [0]*nPer) + nPer2 = 2*nPer + nPer3 = 3*nPer + for i in range(nPer): + s0 = self.arS[i] + s1 = self.arS[i + nPer] + s2 = self.arS[i + nPer2] + s3 = self.arS[i + nPer3] + resArI[i] = 0 + if(_pol == 0): resArI[i] = 0.5*(s0 + s1) #LH + elif(_pol == 1): resArI[i] = 0.5*(s0 - s1) #LV + elif(_pol == 2): resArI[i] = 0.5*(s0 + s2) #L45 + elif(_pol == 3): resArI[i] = 0.5*(s0 - s2) #L135 + elif(_pol == 4): resArI[i] = 0.5*(s0 + s3) #CR (?) + elif(_pol == 5): resArI[i] = 0.5*(s0 - s3) #CL (?) + elif(_pol == 6): resArI[i] = s0 #Total + #else: #to add the case of mutual intensity (what to extract: normal or mutual intensity at a given polarization?) + return resArI + + def to_deg_coh(self, _rel_zer_tol=1.e-04, _rot=True): #05052018 + """Calculates / "extracts" Degree of Coherence from the Mutual Intensity (first Stokes component, s0) + :param _rel_zer_tol: relative zero tolerance to use at normalizing (dividing) by the intensity + :param _rot: rotate or not the degree of coherence data + :return: 1D array with (C-aligned) resulting degree of coherence data + """ + + if(self.mutual <= 0): raise Exception("Calculation of Degree of Coherence can not be done from regular Intensity; Mutual Intensity is required.") + + origNe = self.mesh.ne + origNx = self.mesh.nx + origNy = self.mesh.ny + + origPerEp = 2 + origPerE = origPerEp*origNe + origPerXp = origPerE*origNe + origPerX = origPerXp*origNx + origPerYp = origPerX*origNx + origPerY = origPerYp*origNy + + orig_iec = int(round(0.5*origNe)) + orig_ixc = int(round(0.5*origNx)) + orig_iyc = int(round(0.5*origNy)) + ofstIc = orig_iec*origPerEp + orig_iec*origPerE + orig_ixc*origPerXp + orig_ixc*origPerX + orig_iyc*origPerYp + orig_iyc*origPerY + absZerTolI = abs(self.arS[ofstIc])*_rel_zer_tol + + auxNp = origNe*origNx*origNy + auxNp *= auxNp + resDegCohNonRot = array('f', [0]*auxNp) + + ie2_0_origPerEp_p_ie1_0_origPerE = 0 + ie1_0_origPerEp_p_ie1_0_origPerE = 0 + ie2_0_origPerEp_p_ie2_0_origPerE = 0 + + ix2_0_origPerXp_p_ix1_0_origPerX = 0 + ix1_0_origPerXp_p_ix1_0_origPerX = 0 + ix2_0_origPerXp_p_ix2_0_origPerX = 0 + + iy2_0_origPerYp_p_iy1_0_origPerY = 0 + iy1_0_origPerYp_p_iy1_0_origPerY = 0 + iy2_0_origPerYp_p_iy2_0_origPerY = 0 + + resOfst = 0 + for iy in range(origNy): + for iyp in range(origNy): + if(origNy > 1): + iy1_0_origPerY = iy*origPerY + iy2_0_origPerYp = iyp*origPerYp + iy2_0_origPerYp_p_iy1_0_origPerY = iy2_0_origPerYp + iy1_0_origPerY + iy1_0_origPerYp_p_iy1_0_origPerY = iy*origPerYp + iy1_0_origPerY + iy2_0_origPerYp_p_iy2_0_origPerY = iy2_0_origPerYp + iyp*origPerY + + for ix in range(origNx): + for ixp in range(origNx): + if(origNx > 1): + ix1_0_origPerX = ix*origPerX + ix2_0_origPerXp = ixp*origPerXp + ix2_0_origPerXp_p_ix1_0_origPerX = ix2_0_origPerXp + ix1_0_origPerX + ix1_0_origPerXp_p_ix1_0_origPerX = ix*origPerXp + ix1_0_origPerX + ix2_0_origPerXp_p_ix2_0_origPerX = ix2_0_origPerXp + ixp*origPerX + + if(origNe > 1): + for ie in range(origNe): + for iep in range(origNe): + ie1_0_origPerE = ie*origPerE + ie2_0_origPerEp = iep*origPerEp + ie2_0_origPerEp_p_ie1_0_origPerE = ie2_0_origPerEp + ie1_0_origPerE + ie1_0_origPerEp_p_ie1_0_origPerE = ie*origPerEp + ie1_0_origPerE + ie2_0_origPerEp_p_ie2_0_origPerE = ie2_0_origPerEp + iep*origPerE + + ofstMI = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofstI1 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofstI2 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + + reMI = self.arS[ofstMI]; imMI = self.arS[ofstMI + 1] + absMI = sqrt(reMI*reMI + imMI*imMI) + reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] + reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] + resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + resOfst += 1 + else: + ofstMI = ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofstI1 = ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofstI2 = ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + + reMI = self.arS[ofstMI]; imMI = self.arS[ofstMI + 1] + absMI = sqrt(reMI*reMI + imMI*imMI) + reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] + reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] + resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + resOfst += 1 + + if(not _rot): return resDegCohNonRot + + origEstart = self.mesh.eStart + origEfin = self.mesh.eFin + origXstart = self.mesh.xStart + origXfin = self.mesh.xFin + origYstart = self.mesh.yStart + origYfin = self.mesh.yFin + + origEstep = 0; origEstepInv = 0 + if(origNe > 1): + origEstep = (origEfin - origEstart)/(origNe - 1) + origEstepInv = 1/origEstep + origXstep = 0; origXstepInv = 0 + if(origNx > 1): + origXstep = (origXfin - origXstart)/(origNx - 1) + origXstepInv = 1/origXstep + origYstep = 0; origYstepInv = 0 + if(origNy > 1): + origYstep = (origYfin - origYstart)/(origNy - 1) + origYstepInv = 1/origYstep + + origNe_m_1 = origNe - 1; origNe_m_2 = origNe - 2 + origNx_m_1 = origNx - 1; origNx_m_2 = origNx - 2 + origNy_m_1 = origNy - 1; origNy_m_2 = origNy - 2 + + resNe = origNe + resNx = origNx + resNy = origNy + resEstart = origEstart + resEfin = origEfin + resXstart = origXstart + resXfin = origXfin + resYstart = origYstart + resYfin = origYfin + + #sqrt2 = sqrt(2) + #if(resNe > 1): + # resNe = 2*resNe - 1 + # ec = 0.5*(resEstart + resEfin) + # resEstart = ec - sqrt2*(ec - resEstart) + # resEfin = ec + sqrt2*(resEfin - ec) + #if(resNx > 1): + # resNx = 2*resNx - 1 + # xc = 0.5*(resXstart + resXfin) + # resXstart = xc - sqrt2*(xc - resXstart) + # resXfin = xc + sqrt2*(resXfin - xc) + #if(resNy > 1): + # resNy = 2*resNy - 1 + # yc = 0.5*(resYstart + resYfin) + # resYstart = yc - sqrt2*(yc - resYstart) + # resYfin = yc + sqrt2*(resYfin - yc) + + resNp = resNe*resNx*resNy + resNp *= resNp + resDegCoh = array('f', [0]*resNp) + + resEstep = 0 + if(resNe > 1): resEstep = (resEfin - resEstart)/(resNe - 1) + resXstep = 0 + if(resNx > 1): resXstep = (resXfin - resXstart)/(resNx - 1) + resYstep = 0 + if(resNy > 1): resYstep = (resYfin - resYstart)/(resNy - 1) + + perE = origNe + perXp = perE*origNe + perX = perXp*origNx + perYp = perX*origNx + perY = perYp*origNy + + resX1 = 0; resX2 = 0 #just declaring these vars + resE1 = 0; resE2 = 0 + + ie2_0_p_ie1_0_perE = 0 + ie2_1_p_ie1_0_perE = 0 + ie2_0_p_ie1_1_perE = 0 + ie2_1_p_ie1_1_perE = 0 + + ix2_0_perXp_p_ix1_0_perX = 0 + ix2_1_perXp_p_ix1_0_perX = 0 + ix2_0_perXp_p_ix1_1_perX = 0 + ix2_1_perXp_p_ix1_1_perX = 0 + + iy2_0_perYp_p_iy1_0_perY = 0 + iy2_1_perYp_p_iy1_0_perY = 0 + iy2_0_perYp_p_iy1_1_perY = 0 + iy2_1_perYp_p_iy1_1_perY = 0 + + resOfst = 0 + resYp = resYstart #resY = resYstart + for iyp in range(resNy): #for iy in range(resNy): + resY = resYstart #resYp = resYstart + for iy in range(resNy): #for iyp in range(resNy): + isInRangeY = True + if(resNy > 1): + resY1 = resY + resYp + resY2 = resY - resYp + #resY1 = resY - resYp + #resY2 = resY + resYp + if((resY1 < origYstart) or (resY1 > origYfin) or (resY2 < origYstart) or (resY2 > origYfin)): isInRangeY = False + + iy1_0 = 0; iy1_1 = 0; ry1 = 0 + iy2_0 = 0; iy2_1 = 0; ry2 = 0 + if((resNy > 1) and isInRangeY): + iy1_0 = int(trunc((resY1 - origYstart)*origYstepInv)) + if(iy1_0 >= origNy_m_1): iy1_0 = origNy_m_2 + ry1 = (resY1 - (origYstart + iy1_0*origYstep))*origYstepInv + + iy2_0 = int(trunc((resY2 - origYstart)*origYstepInv)) + if(iy2_0 >= origNy_m_1): iy2_0 = origNy_m_2 + ry2 = (resY2 - (origYstart + iy2_0*origYstep))*origYstepInv + + iy1_1 = iy1_0 + 1 + if(iy1_1 > origNy_m_1): iy1_1 = origNy_m_1 + iy2_1 = iy2_0 + 1 + if(iy2_1 > origNy_m_1): iy2_1 = origNy_m_1 + + iy2_0_perYp = iy2_0*perYp + iy2_1_perYp = iy2_1*perYp + iy1_0_perY = iy1_0*perY + iy1_1_perY = iy1_1*perY + iy2_0_perYp_p_iy1_0_perY = iy2_0_perYp + iy1_0_perY + iy2_1_perYp_p_iy1_0_perY = iy2_1_perYp + iy1_0_perY + iy2_0_perYp_p_iy1_1_perY = iy2_0_perYp + iy1_1_perY + iy2_1_perYp_p_iy1_1_perY = iy2_1_perYp + iy1_1_perY + + resXp = resXstart #resX = resXstart + for ixp in range(resNx): #for ix in range(resNx): + resX = resXstart #resXp = resXstart + for ix in range(resNx): #for ixp in range(resNx): + isInRangeX = True + if(isInRangeY): + if(resNx > 1): + resX1 = resX + resXp + resX2 = resX - resXp + #resX1 = resX - resXp + #resX2 = resX + resXp + if((resX1 < origXstart) or (resX1 > origXfin) or (resX2 < origXstart) or (resX2 > origXfin)): isInRangeX = False + else: + isInRangeX = False + + ix1_0 = 0; ix1_1 = 0; rx1 = 0 + ix2_0 = 0; ix2_1 = 0; rx2 = 0 + if((resNx > 1) and isInRangeX): + ix1_0 = int(trunc((resX1 - origXstart)*origXstepInv)) + if(ix1_0 >= origNx_m_1): ix1_0 = origNx_m_2 + rx1 = (resX1 - (origXstart + ix1_0*origXstep))*origXstepInv + + ix2_0 = int(trunc((resX2 - origXstart)*origXstepInv)) + if(ix2_0 >= origNx_m_1): ix2_0 = origNx_m_2 + rx2 = (resX2 - (origXstart + ix2_0*origXstep))*origXstepInv + + ix1_1 = ix1_0 + 1 + if(ix1_1 > origNx_m_1): ix1_1 = origNx_m_1 + ix2_1 = ix2_0 + 1 + if(ix2_1 > origNx_m_1): ix2_1 = origNx_m_1 + + ix2_0_perXp = ix2_0*perXp + ix2_1_perXp = ix2_1*perXp + ix1_0_perX = ix1_0*perX + ix1_1_perX = ix1_1*perX + ix2_0_perXp_p_ix1_0_perX = ix2_0_perXp + ix1_0_perX + ix2_1_perXp_p_ix1_0_perX = ix2_1_perXp + ix1_0_perX + ix2_0_perXp_p_ix1_1_perX = ix2_0_perXp + ix1_1_perX + ix2_1_perXp_p_ix1_1_perX = ix2_1_perXp + ix1_1_perX + + resEp = resEstart #resE = resEstart + for iep in range(resNe): #for ie in range(resNe): + resE = resEstart #resEp = resEstart + for ie in range(resNe): #for iep in range(resNe): + isInRangeE = True + if(isInRangeX): + if(resNe > 1): + resE1 = resE + resEp + resE2 = resE - resEp + #resE1 = resE - resEp + #resE2 = resE + resEp + if((resE1 < origEstart) or (resE1 > origEfin) or (resE2 < origEstart) or (resE2 > origEfin)): isInRangeE = False + else: + isInRangeE = False + + ie1_0 = 0; ie1_1 = 0; re1 = 0 + ie2_0 = 0; ie2_1 = 0; re2 = 0 + if((resNe > 1) and isInRangeE): + ie1_0 = int(trunc((resE1 - origEstart)*origEstepInv)) + if(ie1_0 >= origNe_m_1): ie1_0 = origNe_m_2 + re1 = (resE1 - (origEstart + ie1_0*origEstep))*origEstepInv + + ie2_0 = int(trunc((resE2 - origEstart)*origEstepInv)) + if(ie2_0 >= origNe_m_1): ie2_0 = origNe_m_2 + re2 = (resE2 - (origEstart + ie2_0*origEstep))*origEstepInv + + ie1_1 = ie1_0 + 1 + if(ie1_1 > origNe_m_1): ie1_1 = origNe_m_1 + ie2_1 = ie2_0 + 1 + if(ie2_1 > origNe_m_1): ie2_1 = origNe_m_1 + + ie1_0_perE = ie1_0*perE + ie1_1_perE = ie1_1*perE + ie2_0_p_ie1_0_perE = ie2_0 + ie1_0_perE + ie2_1_p_ie1_0_perE = ie2_1 + ie1_0_perE + ie2_0_p_ie1_1_perE = ie2_0 + ie1_1_perE + ie2_1_p_ie1_1_perE = ie2_1 + ie1_1_perE + + if(isInRangeE): + a000000 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f100000 = resDegCohNonRot[ie2_1_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f010000 = resDegCohNonRot[ie2_0_p_ie1_1_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f001000 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_1_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f000100 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_1_perX + iy2_0_perYp_p_iy1_0_perY] + f000010 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_1_perYp_p_iy1_0_perY] + f000001 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_1_perY] + + f110000 = resDegCohNonRot[ie2_1_p_ie1_1_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f101000 = resDegCohNonRot[ie2_1_p_ie1_0_perE + ix2_1_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f100100 = resDegCohNonRot[ie2_1_p_ie1_0_perE + ix2_0_perXp_p_ix1_1_perX + iy2_0_perYp_p_iy1_0_perY] + f100010 = resDegCohNonRot[ie2_1_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_1_perYp_p_iy1_0_perY] + f100001 = resDegCohNonRot[ie2_1_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_1_perY] + + f011000 = resDegCohNonRot[ie2_0_p_ie1_1_perE + ix2_1_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_0_perY] + f010100 = resDegCohNonRot[ie2_0_p_ie1_1_perE + ix2_0_perXp_p_ix1_1_perX + iy2_0_perYp_p_iy1_0_perY] + f010010 = resDegCohNonRot[ie2_0_p_ie1_1_perE + ix2_0_perXp_p_ix1_0_perX + iy2_1_perYp_p_iy1_0_perY] + f010001 = resDegCohNonRot[ie2_0_p_ie1_1_perE + ix2_0_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_1_perY] + + f001100 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_1_perXp_p_ix1_1_perX + iy2_0_perYp_p_iy1_0_perY] + f001010 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_1_perXp_p_ix1_0_perX + iy2_1_perYp_p_iy1_0_perY] + f001001 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_1_perXp_p_ix1_0_perX + iy2_0_perYp_p_iy1_1_perY] + + f000110 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_1_perX + iy2_1_perYp_p_iy1_0_perY] + f000101 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_1_perX + iy2_0_perYp_p_iy1_1_perY] + + f000011 = resDegCohNonRot[ie2_0_p_ie1_0_perE + ix2_0_perXp_p_ix1_0_perX + iy2_1_perYp_p_iy1_1_perY] + + a100000 = f100000 - a000000 + a010000 = f010000 - a000000 + a001000 = f001000 - a000000 + a000100 = f000100 - a000000 + a000010 = f000010 - a000000 + a000001 = f000001 - a000000 + a110000 = a000000 - f010000 - f100000 + f110000 + a101000 = a000000 - f001000 - f100000 + f101000 + a100100 = a000000 - f000100 - f100000 + f100100 + a100010 = a000000 - f000010 - f100000 + f100010 + a100001 = a000000 - f000001 - f100000 + f100001 + a011000 = a000000 - f001000 - f010000 + f011000 + a010100 = a000000 - f000100 - f010000 + f010100 + a010010 = a000000 - f000010 - f010000 + f010010 + a010001 = a000000 - f000001 - f010000 + f010001 + a001100 = a000000 - f000100 - f001000 + f001100 + a001010 = a000000 - f000010 - f001000 + f001010 + a001001 = a000000 - f000001 - f001000 + f001001 + a000110 = a000000 - f000010 - f000100 + f000110 + a000101 = a000000 - f000001 - f000100 + f000101 + a000011 = a000000 - f000001 - f000010 + f000011 + + rotDegCoh = (a100000 + a110000*re1 + a101000*rx2 + a100100*rx1 + a100010*ry2 + a100001*ry1)*re2 + rotDegCoh += (a010000 + a011000*rx2 + a010100*rx1 + a010010*ry2 + a010001*ry1)*re1 + rotDegCoh += (a001000 + a001100*rx1 + a001010*ry2 + a001001*ry1)*rx2 + rotDegCoh += (a000100 + a000110*ry2 + a000101*ry1)*rx1 + (a000010 + a000011*ry1)*ry2 + a000001*ry1 + a000000 + #OC05052018: Note that this does not include all terms of multi-dim "bi-linear" interpolation!? + + resDegCoh[resOfst] = rotDegCoh + else: + resDegCoh[resOfst] = 0 + + resOfst += 1 + resE += resEstep #resEp += resEstep + resEp += resEstep #resE += resEstep + resX += resXstep #resXp += resXstep + resXp += resXstep #resX += resXstep + resY += resYstep #resYp += resYstep + resYp += resYstep #resY += resYstep + + return resDegCoh + + def to_deg_coh_slow(self, _rel_zer_tol=1.e-04, _rot=True): + """Calculates / "extracts" Degree of Coherence from the Mutual Intensity (first Stokes component, s0) + :param _rel_zer_tol: relative zero tolerance to use at normalizing (dividing) by the intensity + :param _rot: rotate or not the degree of coherence data + :param _n_stokes_comp: number of Stokes components to treat (1 to 4) + :return: 1D array with (C-aligned) resulting degree of coherence data + """ + + if(self.mutual <= 0): raise Exception("Calculation of Degree of Coherence can not be done from regular Intensity; Mutual Intensity is required.") + + origNe = self.mesh.ne + origNx = self.mesh.nx + origNy = self.mesh.ny + origEstart = self.mesh.eStart + origEfin = self.mesh.eFin + origXstart = self.mesh.xStart + origXfin = self.mesh.xFin + origYstart = self.mesh.yStart + origYfin = self.mesh.xFin + + origEstep = 0; origEstepInv = 0 + if(origNe > 1): + origEstep = (origEfin - origEstart)/(origNe - 1) + origEstepInv = 1/origEstep + origXstep = 0; origXstepInv = 0 + if(origNx > 1): + origXstep = (origXfin - origXstart)/(origNx - 1) + origXstepInv = 1/origXstep + origYstep = 0; origYstepInv = 0 + if(origNy > 1): + origYstep = (origYfin - origYstart)/(origNy - 1) + origYstepInv = 1/origYstep + + origNe_m_1 = origNe - 1; origNe_m_2 = origNe - 2 + origNx_m_1 = origNx - 1; origNx_m_2 = origNx - 2 + origNy_m_1 = origNy - 1; origNy_m_2 = origNy - 2 + + origPerEp = 2 + origPerE = origPerEp*origNe + origPerXp = origPerE*origNe + origPerX = origPerXp*origNx + origPerYp = origPerX*origNx + origPerY = origPerYp*origNy + + orig_iec = int(round(0.5*origNe)) + orig_ixc = int(round(0.5*origNx)) + orig_iyc = int(round(0.5*origNy)) + ofstIc = orig_iec*origPerEp + orig_iec*origPerE + orig_ixc*origPerXp + orig_ixc*origPerX + orig_iyc*origPerYp + orig_iyc*origPerY + absZerTolI = abs(self.arS[ofstIc])*_rel_zer_tol + + resNe = origNe + resNx = origNx + resNy = origNy + resEstart = origEstart + resEfin = origEfin + resXstart = origXstart + resXfin = origXfin + resYstart = origYstart + resYfin = origYfin + + if(_rot): + sqrt2 = sqrt(2) + + if(resNe > 1): + resNe = 2*resNe - 1 + ec = 0.5*(resEstart + resEfin) + resEstart = ec - sqrt2*(ec - resEstart) + resEfin = ec + sqrt2*(resEfin - ec) + + if(resNx > 1): + resNx = 2*resNx - 1 + xc = 0.5*(resXstart + resXfin) + resXstart = xc - sqrt2*(xc - resXstart) + resXfin = xc + sqrt2*(resXfin - xc) + + if(resNy > 1): + resNy = 2*resNy - 1 + yc = 0.5*(resYstart + resYfin) + resYstart = yc - sqrt2*(yc - resYstart) + resYfin = yc + sqrt2*(resYfin - yc) + + resNp = resNe*resNx*resNy + resNp *= resNp + resDegCoh = array('f', [0]*resNp) + + resEstep = 0 + if(resNe > 1): resEstep = (resEfin - resEstart)/(resNe - 1) + resXstep = 0 + if(resNx > 1): resXstep = (resXfin - resXstart)/(resNx - 1) + resYstep = 0 + if(resNy > 1): resYstep = (resYfin - resYstart)/(resNy - 1) + + resX1 = 0; resX2 = 0 #just declaring these vars + resE1 = 0; resE2 = 0 #just declaring these vars + + ie2_0_origPerEp_p_ie1_0_origPerE = 0 + ie2_1_origPerEp_p_ie1_0_origPerE = 0 + ie2_0_origPerEp_p_ie1_1_origPerE = 0 + ie2_1_origPerEp_p_ie1_1_origPerE = 0 + + ie1_0_origPerEp_p_ie1_0_origPerE = 0 + ie1_1_origPerEp_p_ie1_0_origPerE = 0 + ie1_0_origPerEp_p_ie1_1_origPerE = 0 + ie1_1_origPerEp_p_ie1_1_origPerE = 0 + + ie2_0_origPerEp_p_ie2_0_origPerE = 0 + ie2_1_origPerEp_p_ie2_0_origPerE = 0 + ie2_0_origPerEp_p_ie2_1_origPerE = 0 + ie2_1_origPerEp_p_ie2_1_origPerE = 0 + + ix2_0_origPerXp_p_ix1_0_origPerX = 0 + ix2_1_origPerXp_p_ix1_0_origPerX = 0 + ix2_0_origPerXp_p_ix1_1_origPerX = 0 + ix2_1_origPerXp_p_ix1_1_origPerX = 0 + + ix1_0_origPerXp_p_ix1_0_origPerX = 0 + ix1_1_origPerXp_p_ix1_0_origPerX = 0 + ix1_0_origPerXp_p_ix1_1_origPerX = 0 + ix1_1_origPerXp_p_ix1_1_origPerX = 0 + + ix2_0_origPerXp_p_ix2_0_origPerX = 0 + ix2_1_origPerXp_p_ix2_0_origPerX = 0 + ix2_0_origPerXp_p_ix2_1_origPerX = 0 + ix2_1_origPerXp_p_ix2_1_origPerX = 0 + + iy2_0_origPerYp_p_iy1_0_origPerY = 0 + iy2_1_origPerYp_p_iy1_0_origPerY = 0 + iy2_0_origPerYp_p_iy1_1_origPerY = 0 + iy2_1_origPerYp_p_iy1_1_origPerY = 0 + + iy1_0_origPerYp_p_iy1_0_origPerY = 0 + iy1_1_origPerYp_p_iy1_0_origPerY = 0 + iy1_0_origPerYp_p_iy1_1_origPerY = 0 + iy1_1_origPerYp_p_iy1_1_origPerY = 0 + + iy2_0_origPerYp_p_iy2_0_origPerY = 0 + iy2_1_origPerYp_p_iy2_0_origPerY = 0 + iy2_0_origPerYp_p_iy2_1_origPerY = 0 + iy2_1_origPerYp_p_iy2_1_origPerY = 0 + + resOfst = 0 + resY = resYstart + for iy in range(resNy): + resYp = resYstart + for iyp in range(resNy): + isInRangeY = True + if(_rot and (resNy > 1)): + resY1 = resY + resYp + resY2 = resY - resYp + #resY1 = resY - resYp + #resY2 = resY + resYp + if((resY1 < origYstart) or (resY1 > origYfin) or (resY2 < origYstart) or (resY2 > origYfin)): isInRangeY = False + + iy1_0 = 0; iy1_1 = 0; ry1 = 0 + iy2_0 = 0; iy2_1 = 0; ry2 = 0 + if(_rot): + if((resNy > 1) and isInRangeY): + iy1_0 = int(trunc((resY1 - origYstart)*origYstepInv)) + if(iy1_0 >= origNy_m_1): iy1_0 = origNy_m_2 + ry1 = (resY1 - (origYstart + iy1_0*origYstep))*origYstepInv + + iy2_0 = int(trunc((resY2 - origYstart)*origYstepInv)) + if(iy2_0 >= origNy_m_1): iy2_0 = origNy_m_2 + ry2 = (resY2 - (origYstart + iy2_0*origYstep))*origYstepInv + + iy1_1 = iy1_0 + 1 + if(iy1_1 > origNy_m_1): iy1_1 = origNy_m_1 + iy2_1 = iy2_0 + 1 + if(iy2_1 > origNy_m_1): iy2_1 = origNy_m_1 + + iy2_0_origPerYp = iy2_0*origPerYp + iy2_1_origPerYp = iy2_1*origPerYp + iy1_0_origPerY = iy1_0*origPerY + iy1_1_origPerY = iy1_1*origPerY + iy2_0_origPerYp_p_iy1_0_origPerY = iy2_0_origPerYp + iy1_0_origPerY + iy2_1_origPerYp_p_iy1_0_origPerY = iy2_1_origPerYp + iy1_0_origPerY + iy2_0_origPerYp_p_iy1_1_origPerY = iy2_0_origPerYp + iy1_1_origPerY + iy2_1_origPerYp_p_iy1_1_origPerY = iy2_1_origPerYp + iy1_1_origPerY + iy1_0_origPerYp = iy1_0*origPerYp + iy1_1_origPerYp = iy1_1*origPerYp + iy1_0_origPerYp_p_iy1_0_origPerY = iy1_0_origPerYp + iy1_0_origPerY + iy1_1_origPerYp_p_iy1_0_origPerY = iy1_1_origPerYp + iy1_0_origPerY + iy1_0_origPerYp_p_iy1_1_origPerY = iy1_0_origPerYp + iy1_1_origPerY + iy1_1_origPerYp_p_iy1_1_origPerY = iy1_1_origPerYp + iy1_1_origPerY + iy2_0_origPerY = iy2_0*origPerY + iy2_1_origPerY = iy2_1*origPerY + iy2_0_origPerYp_p_iy2_0_origPerY = iy2_0_origPerYp + iy2_0_origPerY + iy2_1_origPerYp_p_iy2_0_origPerY = iy2_1_origPerYp + iy2_0_origPerY + iy2_0_origPerYp_p_iy2_1_origPerY = iy2_0_origPerYp + iy2_1_origPerY + iy2_1_origPerYp_p_iy2_1_origPerY = iy2_1_origPerYp + iy2_1_origPerY + else: + iy1_0 = iy + iy2_0 = iyp + iy2_0_origPerYp = iy2_0*origPerYp + iy1_0_origPerY = iy1_0*origPerY + iy2_0_origPerYp_p_iy1_0_origPerY = iy2_0_origPerYp + iy1_0_origPerY + iy1_0_origPerYp_p_iy1_0_origPerY = iy1_0*origPerYp + iy1_0_origPerY + iy2_0_origPerYp_p_iy2_0_origPerY = iy2_0_origPerYp + iy2_0*origPerY + + resX = resXstart + for ix in range(resNx): + resXp = resXstart + for ixp in range(resNx): + isInRangeX = True + if(isInRangeY): + if(_rot and (resNx > 1)): + resX1 = resX + resXp + resX2 = resX - resXp + #resX1 = resX - resXp + #resX2 = resX + resXp + if((resX1 < origXstart) or (resX1 > origXfin) or (resX2 < origXstart) or (resX2 > origXfin)): isInRangeX = False + else: + isInRangeX = False + + ix1_0 = 0; ix1_1 = 0; rx1 = 0 + ix2_0 = 0; ix2_1 = 0; rx2 = 0 + if(_rot): + if((resNx > 1) and isInRangeX): + ix1_0 = int(trunc((resX1 - origXstart)*origXstepInv)) + if(ix1_0 >= origNx_m_1): ix1_0 = origNx_m_2 + rx1 = (resX1 - (origXstart + ix1_0*origXstep))*origXstepInv + + ix2_0 = int(trunc((resX2 - origXstart)*origXstepInv)) + if(ix2_0 >= origNx_m_1): ix2_0 = origNx_m_2 + rx2 = (resX2 - (origXstart + ix2_0*origXstep))*origXstepInv + + ix1_1 = ix1_0 + 1 + if(ix1_1 > origNx_m_1): ix1_1 = origNx_m_1 + ix2_1 = ix2_0 + 1 + if(ix2_1 > origNx_m_1): ix2_1 = origNx_m_1 + + ix2_0_origPerXp = ix2_0*origPerXp + ix2_1_origPerXp = ix2_1*origPerXp + ix1_0_origPerX = ix1_0*origPerX + ix1_1_origPerX = ix1_1*origPerX + ix2_0_origPerXp_p_ix1_0_origPerX = ix2_0_origPerXp + ix1_0_origPerX + ix2_1_origPerXp_p_ix1_0_origPerX = ix2_1_origPerXp + ix1_0_origPerX + ix2_0_origPerXp_p_ix1_1_origPerX = ix2_0_origPerXp + ix1_1_origPerX + ix2_1_origPerXp_p_ix1_1_origPerX = ix2_1_origPerXp + ix1_1_origPerX + ix1_0_origPerXp = ix1_0*origPerXp + ix1_1_origPerXp = ix1_1*origPerXp + ix1_0_origPerXp_p_ix1_0_origPerX = ix1_0_origPerXp + ix1_0_origPerX + ix1_1_origPerXp_p_ix1_0_origPerX = ix1_1_origPerXp + ix1_0_origPerX + ix1_0_origPerXp_p_ix1_1_origPerX = ix1_0_origPerXp + ix1_1_origPerX + ix1_1_origPerXp_p_ix1_1_origPerX = ix1_1_origPerXp + ix1_1_origPerX + ix2_0_origPerX = ix2_0*origPerX + ix2_1_origPerX = ix2_1*origPerX + ix2_0_origPerXp_p_ix2_0_origPerX = ix2_0_origPerXp + ix2_0_origPerX + ix2_1_origPerXp_p_ix2_0_origPerX = ix2_1_origPerXp + ix2_0_origPerX + ix2_0_origPerXp_p_ix2_1_origPerX = ix2_0_origPerXp + ix2_1_origPerX + ix2_1_origPerXp_p_ix2_1_origPerX = ix2_1_origPerXp + ix2_1_origPerX + else: + ix1_0 = ix + ix2_0 = ixp + ix2_0_origPerXp = ix2_0*origPerXp + ix1_0_origPerX = ix1_0*origPerX + ix2_0_origPerXp_p_ix1_0_origPerX = ix2_0_origPerXp + ix1_0_origPerX + ix1_0_origPerXp_p_ix1_0_origPerX = ix1_0*origPerXp + ix1_0_origPerX + ix2_0_origPerXp_p_ix2_0_origPerX = ix2_0_origPerXp + ix2_0*origPerX + + resE = resEstart + for ie in range(resNe): + resEp = resEstart + for iep in range(resNe): + isInRangeE = True + if(isInRangeX): + if(_rot and (resNe > 1)): + resE1 = resE + resEp + resE2 = resE - resEp + #resE1 = resE - resEp + #resE2 = resE + resEp + if((resE1 < origEstart) or (resE1 > origEfin) or (resE2 < origEstart) or (resE2 > origEfin)): isInRangeE = False + else: + isInRangeE = False + + ie1_0 = 0; ie1_1 = 0; re1 = 0 + ie2_0 = 0; ie2_1 = 0; re2 = 0 + if(_rot): + if((resNe > 1) and isInRangeE): + ie1_0 = int(trunc((resE1 - origEstart)*origEstepInv)) + if(ie1_0 >= origNe_m_1): ie1_0 = origNe_m_2 + re1 = (resE1 - (origEstart + ie1_0*origEstep))*origEstepInv + + ie2_0 = int(trunc((resE2 - origEstart)*origEstepInv)) + if(ie2_0 >= origNe_m_1): ie2_0 = origNe_m_2 + re2 = (resE2 - (origEstart + ie2_0*origEstep))*origEstepInv + + ie1_1 = ie1_0 + 1 + if(ie1_1 > origNe_m_1): ie1_1 = origNe_m_1 + ie2_1 = ie2_0 + 1 + if(ie2_1 > origNe_m_1): ie2_1 = origNe_m_1 + + ie2_0_origPerEp = ie2_0*origPerEp + ie2_1_origPerEp = ie2_1*origPerEp + ie1_0_origPerE = ie1_0*origPerE + ie1_1_origPerE = ie1_1*origPerE + ie2_0_origPerEp_p_ie1_0_origPerE = ie2_0_origPerEp + ie1_0_origPerE + ie2_1_origPerEp_p_ie1_0_origPerE = ie2_1_origPerEp + ie1_0_origPerE + ie2_0_origPerEp_p_ie1_1_origPerE = ie2_0_origPerEp + ie1_1_origPerE + ie2_1_origPerEp_p_ie1_1_origPerE = ie2_1_origPerEp + ie1_1_origPerE + ie1_0_origPerEp = ie1_0*origPerEp + ie1_1_origPerEp = ie1_1*origPerEp + ie1_0_origPerEp_p_ie1_0_origPerE = ie1_0_origPerEp + ie1_0_origPerE + ie1_1_origPerEp_p_ie1_0_origPerE = ie1_1_origPerEp + ie1_0_origPerE + ie1_0_origPerEp_p_ie1_1_origPerE = ie1_0_origPerEp + ie1_1_origPerE + ie1_1_origPerEp_p_ie1_1_origPerE = ie1_1_origPerEp + ie1_1_origPerE + ie2_0_origPerE = ie2_0*origPerE + ie2_1_origPerE = ie2_1*origPerE + ie2_0_origPerEp_p_ie2_0_origPerE = ie2_0_origPerEp + ie2_0_origPerE + ie2_1_origPerEp_p_ie2_0_origPerE = ie2_1_origPerEp + ie2_0_origPerE + ie2_0_origPerEp_p_ie2_1_origPerE = ie2_0_origPerEp + ie2_1_origPerE + ie2_1_origPerEp_p_ie2_1_origPerE = ie2_1_origPerEp + ie2_1_origPerE + + if(isInRangeE): + #--------------MI + ofst000000 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst100000 = ie2_1_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst010000 = ie2_0_origPerEp_p_ie1_1_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst001000 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_1_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst000100 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_1_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst000010 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_1_origPerYp_p_iy1_0_origPerY + ofst000001 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_1_origPerY + + ofst110000 = ie2_1_origPerEp_p_ie1_1_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst101000 = ie2_1_origPerEp_p_ie1_0_origPerE + ix2_1_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst100100 = ie2_1_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_1_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst100010 = ie2_1_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_1_origPerYp_p_iy1_0_origPerY + ofst100001 = ie2_1_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_1_origPerY + + ofst011000 = ie2_0_origPerEp_p_ie1_1_origPerE + ix2_1_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst010100 = ie2_0_origPerEp_p_ie1_1_origPerE + ix2_0_origPerXp_p_ix1_1_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst010010 = ie2_0_origPerEp_p_ie1_1_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_1_origPerYp_p_iy1_0_origPerY + ofst010001 = ie2_0_origPerEp_p_ie1_1_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_1_origPerY + + ofst001100 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_1_origPerXp_p_ix1_1_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY + ofst001010 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_1_origPerXp_p_ix1_0_origPerX + iy2_1_origPerYp_p_iy1_0_origPerY + ofst001001 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_1_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_1_origPerY + + ofst000110 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_1_origPerX + iy2_1_origPerYp_p_iy1_0_origPerY + ofst000101 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_1_origPerX + iy2_0_origPerYp_p_iy1_1_origPerY + + ofst000011 = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0_origPerXp_p_ix1_0_origPerX + iy2_1_origPerYp_p_iy1_1_origPerY + + re_a000000 = _more_stokes.arS[ofst000000]; ofst000000 += 1; im_a000000 = _more_stokes.arS[ofst000000] + re_f100000 = _more_stokes.arS[ofst100000]; ofst100000 += 1; im_f100000 = _more_stokes.arS[ofst100000] + re_f010000 = _more_stokes.arS[ofst010000]; ofst010000 += 1; im_f010000 = _more_stokes.arS[ofst010000] + re_f001000 = _more_stokes.arS[ofst001000]; ofst001000 += 1; im_f001000 = _more_stokes.arS[ofst001000] + re_f000100 = _more_stokes.arS[ofst000100]; ofst000100 += 1; im_f000100 = _more_stokes.arS[ofst000100] + re_f000010 = _more_stokes.arS[ofst000010]; ofst000010 += 1; im_f000010 = _more_stokes.arS[ofst000010] + re_f000001 = _more_stokes.arS[ofst000001]; ofst000001 += 1; im_f000001 = _more_stokes.arS[ofst000001] + + re_f110000 = _more_stokes.arS[ofst110000]; ofst110000 += 1; im_f110000 = _more_stokes.arS[ofst110000] + re_f101000 = _more_stokes.arS[ofst101000]; ofst101000 += 1; im_f101000 = _more_stokes.arS[ofst101000] + re_f100100 = _more_stokes.arS[ofst100100]; ofst100100 += 1; im_f100100 = _more_stokes.arS[ofst100100] + re_f100010 = _more_stokes.arS[ofst100010]; ofst100010 += 1; im_f100010 = _more_stokes.arS[ofst100010] + re_f100001 = _more_stokes.arS[ofst100001]; ofst100001 += 1; im_f100001 = _more_stokes.arS[ofst100001] + + re_f011000 = _more_stokes.arS[ofst011000]; ofst011000 += 1; im_f011000 = _more_stokes.arS[ofst011000] + re_f010100 = _more_stokes.arS[ofst010100]; ofst010100 += 1; im_f010100 = _more_stokes.arS[ofst010100] + re_f010010 = _more_stokes.arS[ofst010010]; ofst010010 += 1; im_f010010 = _more_stokes.arS[ofst010010] + re_f010001 = _more_stokes.arS[ofst010001]; ofst010001 += 1; im_f010001 = _more_stokes.arS[ofst010001] + + re_f001100 = _more_stokes.arS[ofst001100]; ofst001100 += 1; im_f001100 = _more_stokes.arS[ofst001100] + re_f001010 = _more_stokes.arS[ofst001010]; ofst001010 += 1; im_f001010 = _more_stokes.arS[ofst001010] + re_f001001 = _more_stokes.arS[ofst001001]; ofst001001 += 1; im_f001001 = _more_stokes.arS[ofst001001] + + re_f000110 = _more_stokes.arS[ofst000110]; ofst000110 += 1; im_f000110 = _more_stokes.arS[ofst000110] + re_f000101 = _more_stokes.arS[ofst000101]; ofst000101 += 1; im_f000101 = _more_stokes.arS[ofst000101] + + re_f000011 = _more_stokes.arS[ofst000011]; ofst000011 += 1; im_f000011 = _more_stokes.arS[ofst000011] + + re_a100000 = re_f100000 - re_a000000; im_a100000 = im_f100000 - im_a000000 + re_a010000 = re_f010000 - re_a000000; im_a010000 = im_f010000 - im_a000000 + re_a001000 = re_f001000 - re_a000000; im_a001000 = im_f001000 - im_a000000 + re_a000100 = re_f000100 - re_a000000; im_a000100 = im_f000100 - im_a000000 + re_a000010 = re_f000010 - re_a000000; im_a000010 = im_f000010 - im_a000000 + re_a000001 = re_f000001 - re_a000000; im_a000001 = im_f000001 - im_a000000 + re_a110000 = re_a000000 - re_f010000 - re_f100000 + re_f110000; im_a110000 = im_a000000 - im_f010000 - im_f100000 + im_f110000 + re_a101000 = re_a000000 - re_f001000 - re_f100000 + re_f101000; im_a101000 = im_a000000 - im_f001000 - im_f100000 + im_f101000 + re_a100100 = re_a000000 - re_f000100 - re_f100000 + re_f100100; im_a100100 = im_a000000 - im_f000100 - im_f100000 + im_f100100 + re_a100010 = re_a000000 - re_f000010 - re_f100000 + re_f100010; im_a100010 = im_a000000 - im_f000010 - im_f100000 + im_f100010 + re_a100001 = re_a000000 - re_f000001 - re_f100000 + re_f100001; im_a100001 = im_a000000 - im_f000001 - im_f100000 + im_f100001 + re_a011000 = re_a000000 - re_f001000 - re_f010000 + re_f011000; im_a011000 = im_a000000 - im_f001000 - im_f010000 + im_f011000 + re_a010100 = re_a000000 - re_f000100 - re_f010000 + re_f010100; im_a010100 = im_a000000 - im_f000100 - im_f010000 + im_f010100 + re_a010010 = re_a000000 - re_f000010 - re_f010000 + re_f010010; im_a010010 = im_a000000 - im_f000010 - im_f010000 + im_f010010 + re_a010001 = re_a000000 - re_f000001 - re_f010000 + re_f010001; im_a010001 = im_a000000 - im_f000001 - im_f010000 + im_f010001 + re_a001100 = re_a000000 - re_f000100 - re_f001000 + re_f001100; im_a001100 = im_a000000 - im_f000100 - im_f001000 + im_f001100 + re_a001010 = re_a000000 - re_f000010 - re_f001000 + re_f001010; im_a001010 = im_a000000 - im_f000010 - im_f001000 + im_f001010 + re_a001001 = re_a000000 - re_f000001 - re_f001000 + re_f001001; im_a001001 = im_a000000 - im_f000001 - im_f001000 + im_f001001 + re_a000110 = re_a000000 - re_f000010 - re_f000100 + re_f000110; im_a000110 = im_a000000 - im_f000010 - im_f000100 + im_f000110 + re_a000101 = re_a000000 - re_f000001 - re_f000100 + re_f000101; im_a000101 = im_a000000 - im_f000001 - im_f000100 + im_f000101 + re_a000011 = re_a000000 - re_f000001 - re_f000010 + re_f000011; im_a000011 = im_a000000 - im_f000001 - im_f000010 + im_f000011 + + reMI = (re_a100000 + re_a110000*re1 + re_a101000*rx2 + re_a100100*rx1 + re_a100010*ry2 + re_a100001*ry1)*re2 + reMI += (re_a010000 + re_a011000*rx2 + re_a010100*rx1 + re_a010010*ry2 + re_a010001*ry1)*re1 + reMI += (re_a001000 + re_a001100*rx1 + re_a001010*ry2 + re_a001001*ry1)*rx2 + reMI += (re_a000100 + re_a000110*ry2 + re_a000101*ry1)*rx1 + (re_a000010 + re_a000011*ry1)*ry2 + re_a000001*ry1 + re_a000000 + imMI = (im_a100000 + im_a110000*re1 + im_a101000*rx2 + im_a100100*rx1 + im_a100010*ry2 + im_a100001*ry1)*re2 + imMI += (im_a010000 + im_a011000*rx2 + im_a010100*rx1 + im_a010010*ry2 + im_a010001*ry1)*re1 + imMI += (im_a001000 + im_a001100*rx1 + im_a001010*ry2 + im_a001001*ry1)*rx2 + imMI += (im_a000100 + im_a000110*ry2 + im_a000101*ry1)*rx1 + (im_a000010 + im_a000011*ry1)*ry2 + im_a000001*ry1 + im_a000000 + absMI = sqrt(reMI*reMI + imMI*imMI) + + #--------------I1 + ofst000000 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst100000 = ie1_1_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst010000 = ie1_0_origPerEp_p_ie1_1_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst001000 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_1_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst000100 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_1_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst000010 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_1_origPerYp_p_iy1_0_origPerY + ofst000001 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_1_origPerY + + ofst110000 = ie1_1_origPerEp_p_ie1_1_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst101000 = ie1_1_origPerEp_p_ie1_0_origPerE + ix1_1_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst100100 = ie1_1_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_1_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst100010 = ie1_1_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_1_origPerYp_p_iy1_0_origPerY + ofst100001 = ie1_1_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_1_origPerY + + ofst011000 = ie1_0_origPerEp_p_ie1_1_origPerE + ix1_1_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst010100 = ie1_0_origPerEp_p_ie1_1_origPerE + ix1_0_origPerXp_p_ix1_1_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst010010 = ie1_0_origPerEp_p_ie1_1_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_1_origPerYp_p_iy1_0_origPerY + ofst010001 = ie1_0_origPerEp_p_ie1_1_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_1_origPerY + + ofst001100 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_1_origPerXp_p_ix1_1_origPerX + iy1_0_origPerYp_p_iy1_0_origPerY + ofst001010 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_1_origPerXp_p_ix1_0_origPerX + iy1_1_origPerYp_p_iy1_0_origPerY + ofst001001 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_1_origPerXp_p_ix1_0_origPerX + iy1_0_origPerYp_p_iy1_1_origPerY + + ofst000110 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_1_origPerX + iy1_1_origPerYp_p_iy1_0_origPerY + ofst000101 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_1_origPerX + iy1_0_origPerYp_p_iy1_1_origPerY + + ofst000011 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0_origPerXp_p_ix1_0_origPerX + iy1_1_origPerYp_p_iy1_1_origPerY + + re_a000000 = _more_stokes.arS[ofst000000]#; ofst000000 += 1; im_a000000 = _more_stokes.arS[ofst000000] + re_f100000 = _more_stokes.arS[ofst100000]#; ofst100000 += 1; im_f100000 = _more_stokes.arS[ofst100000] + re_f010000 = _more_stokes.arS[ofst010000]#; ofst010000 += 1; im_f010000 = _more_stokes.arS[ofst010000] + re_f001000 = _more_stokes.arS[ofst001000]#; ofst001000 += 1; im_f001000 = _more_stokes.arS[ofst001000] + re_f000100 = _more_stokes.arS[ofst000100]#; ofst000100 += 1; im_f000100 = _more_stokes.arS[ofst000100] + re_f000010 = _more_stokes.arS[ofst000010]#; ofst000010 += 1; im_f000010 = _more_stokes.arS[ofst000010] + re_f000001 = _more_stokes.arS[ofst000001]#; ofst000001 += 1; im_f000001 = _more_stokes.arS[ofst000001] + + re_f110000 = _more_stokes.arS[ofst110000]#; ofst110000 += 1; im_f110000 = _more_stokes.arS[ofst110000] + re_f101000 = _more_stokes.arS[ofst101000]#; ofst101000 += 1; im_f101000 = _more_stokes.arS[ofst101000] + re_f100100 = _more_stokes.arS[ofst100100]#; ofst100100 += 1; im_f100100 = _more_stokes.arS[ofst100100] + re_f100010 = _more_stokes.arS[ofst100010]#; ofst100010 += 1; im_f100010 = _more_stokes.arS[ofst100010] + re_f100001 = _more_stokes.arS[ofst100001]#; ofst100001 += 1; im_f100001 = _more_stokes.arS[ofst100001] + + re_f011000 = _more_stokes.arS[ofst011000]#; ofst011000 += 1; im_f011000 = _more_stokes.arS[ofst011000] + re_f010100 = _more_stokes.arS[ofst010100]#; ofst010100 += 1; im_f010100 = _more_stokes.arS[ofst010100] + re_f010010 = _more_stokes.arS[ofst010010]#; ofst010010 += 1; im_f010010 = _more_stokes.arS[ofst010010] + re_f010001 = _more_stokes.arS[ofst010001]#; ofst010001 += 1; im_f010001 = _more_stokes.arS[ofst010001] + + re_f001100 = _more_stokes.arS[ofst001100]#; ofst001100 += 1; im_f001100 = _more_stokes.arS[ofst001100] + re_f001010 = _more_stokes.arS[ofst001010]#; ofst001010 += 1; im_f001010 = _more_stokes.arS[ofst001010] + re_f001001 = _more_stokes.arS[ofst001001]#; ofst001001 += 1; im_f001001 = _more_stokes.arS[ofst001001] + + re_f000110 = _more_stokes.arS[ofst000110]#; ofst000110 += 1; im_f000110 = _more_stokes.arS[ofst000110] + re_f000101 = _more_stokes.arS[ofst000101]#; ofst000101 += 1; im_f000101 = _more_stokes.arS[ofst000101] + + re_f000011 = _more_stokes.arS[ofst000011]#; ofst000011 += 1; im_f000011 = _more_stokes.arS[ofst000011] + + re_a100000 = re_f100000 - re_a000000#; im_a100000 = im_f100000 - im_a000000 + re_a010000 = re_f010000 - re_a000000#; im_a010000 = im_f010000 - im_a000000 + re_a001000 = re_f001000 - re_a000000#; im_a001000 = im_f001000 - im_a000000 + re_a000100 = re_f000100 - re_a000000#; im_a000100 = im_f000100 - im_a000000 + re_a000010 = re_f000010 - re_a000000#; im_a000010 = im_f000010 - im_a000000 + re_a000001 = re_f000001 - re_a000000#; im_a000001 = im_f000001 - im_a000000 + re_a110000 = re_a000000 - re_f010000 - re_f100000 + re_f110000#; im_a110000 = im_a000000 - im_f010000 - im_f100000 + im_f110000 + re_a101000 = re_a000000 - re_f001000 - re_f100000 + re_f101000#; im_a101000 = im_a000000 - im_f001000 - im_f100000 + im_f101000 + re_a100100 = re_a000000 - re_f000100 - re_f100000 + re_f100100#; im_a100100 = im_a000000 - im_f000100 - im_f100000 + im_f100100 + re_a100010 = re_a000000 - re_f000010 - re_f100000 + re_f100010#; im_a100010 = im_a000000 - im_f000010 - im_f100000 + im_f100010 + re_a100001 = re_a000000 - re_f000001 - re_f100000 + re_f100001#; im_a100001 = im_a000000 - im_f000001 - im_f100000 + im_f100001 + re_a011000 = re_a000000 - re_f001000 - re_f010000 + re_f011000#; im_a011000 = im_a000000 - im_f001000 - im_f010000 + im_f011000 + re_a010100 = re_a000000 - re_f000100 - re_f010000 + re_f010100#; im_a010100 = im_a000000 - im_f000100 - im_f010000 + im_f010100 + re_a010010 = re_a000000 - re_f000010 - re_f010000 + re_f010010#; im_a010010 = im_a000000 - im_f000010 - im_f010000 + im_f010010 + re_a010001 = re_a000000 - re_f000001 - re_f010000 + re_f010001#; im_a010001 = im_a000000 - im_f000001 - im_f010000 + im_f010001 + re_a001100 = re_a000000 - re_f000100 - re_f001000 + re_f001100#; im_a001100 = im_a000000 - im_f000100 - im_f001000 + im_f001100 + re_a001010 = re_a000000 - re_f000010 - re_f001000 + re_f001010#; im_a001010 = im_a000000 - im_f000010 - im_f001000 + im_f001010 + re_a001001 = re_a000000 - re_f000001 - re_f001000 + re_f001001#; im_a001001 = im_a000000 - im_f000001 - im_f001000 + im_f001001 + re_a000110 = re_a000000 - re_f000010 - re_f000100 + re_f000110#; im_a000110 = im_a000000 - im_f000010 - im_f000100 + im_f000110 + re_a000101 = re_a000000 - re_f000001 - re_f000100 + re_f000101#; im_a000101 = im_a000000 - im_f000001 - im_f000100 + im_f000101 + re_a000011 = re_a000000 - re_f000001 - re_f000010 + re_f000011#; im_a000011 = im_a000000 - im_f000001 - im_f000010 + im_f000011 + + reI1 = (re_a100000 + re_a110000*re1 + (re_a101000 + re_a100100)*rx1 + (re_a100010 + re_a100001)*ry1)*re1 + reI1 += (re_a010000 + (re_a011000 + re_a010100)*rx1 + (re_a010010 + re_a010001)*ry1)*re1 + reI1 += (re_a001000 + re_a001100*rx1 + (re_a001010 + re_a001001)*ry1)*rx1 + reI1 += (re_a000100 + (re_a000110 + re_a000101)*ry1)*rx1 + (re_a000010 + re_a000011*ry1)*ry1 + re_a000001*ry1 + re_a000000 + #imI1 = (im_a100000 + im_a110000*re1 + (im_a101000 + im_a100100)*rx1 + (im_a100010 + im_a100001)*ry1)*re1 + #imI1 += (im_a010000 + (im_a011000 + im_a010100)*rx1 + (im_a010010 + im_a010001)*ry1)*re1 + #imI1 += (im_a001000 + im_a001100*rx1 + (im_a001010 + im_a001001)*ry1)*rx1 + #imI1 += (im_a000100 + (im_a000110 + im_a000101)*ry1)*rx1 + (im_a000010 + im_a000011*ry1)*ry1 + im_a000001*ry1 + im_a000000 + + #--------------I2 + ofst000000 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst100000 = ie2_1_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst010000 = ie2_0_origPerEp_p_ie2_1_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst001000 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_1_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst000100 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_1_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst000010 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_1_origPerYp_p_iy2_0_origPerY + ofst000001 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_1_origPerY + + ofst110000 = ie2_1_origPerEp_p_ie2_1_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst101000 = ie2_1_origPerEp_p_ie2_0_origPerE + ix2_1_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst100100 = ie2_1_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_1_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst100010 = ie2_1_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_1_origPerYp_p_iy2_0_origPerY + ofst100001 = ie2_1_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_1_origPerY + + ofst011000 = ie2_0_origPerEp_p_ie2_1_origPerE + ix2_1_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst010100 = ie2_0_origPerEp_p_ie2_1_origPerE + ix2_0_origPerXp_p_ix2_1_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst010010 = ie2_0_origPerEp_p_ie2_1_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_1_origPerYp_p_iy2_0_origPerY + ofst010001 = ie2_0_origPerEp_p_ie2_1_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_1_origPerY + + ofst001100 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_1_origPerXp_p_ix2_1_origPerX + iy2_0_origPerYp_p_iy2_0_origPerY + ofst001010 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_1_origPerXp_p_ix2_0_origPerX + iy2_1_origPerYp_p_iy2_0_origPerY + ofst001001 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_1_origPerXp_p_ix2_0_origPerX + iy2_0_origPerYp_p_iy2_1_origPerY + + ofst000110 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_1_origPerX + iy2_1_origPerYp_p_iy2_0_origPerY + ofst000101 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_1_origPerX + iy2_0_origPerYp_p_iy2_1_origPerY + + ofst000011 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0_origPerXp_p_ix2_0_origPerX + iy2_1_origPerYp_p_iy2_1_origPerY + + re_a000000 = _more_stokes.arS[ofst000000]#; ofst000000 += 1; im_a000000 = _more_stokes.arS[ofst000000] + re_f100000 = _more_stokes.arS[ofst100000]#; ofst100000 += 1; im_f100000 = _more_stokes.arS[ofst100000] + re_f010000 = _more_stokes.arS[ofst010000]#; ofst010000 += 1; im_f010000 = _more_stokes.arS[ofst010000] + re_f001000 = _more_stokes.arS[ofst001000]#; ofst001000 += 1; im_f001000 = _more_stokes.arS[ofst001000] + re_f000100 = _more_stokes.arS[ofst000100]#; ofst000100 += 1; im_f000100 = _more_stokes.arS[ofst000100] + re_f000010 = _more_stokes.arS[ofst000010]#; ofst000010 += 1; im_f000010 = _more_stokes.arS[ofst000010] + re_f000001 = _more_stokes.arS[ofst000001]#; ofst000001 += 1; im_f000001 = _more_stokes.arS[ofst000001] + + re_f110000 = _more_stokes.arS[ofst110000]#; ofst110000 += 1; im_f110000 = _more_stokes.arS[ofst110000] + re_f101000 = _more_stokes.arS[ofst101000]#; ofst101000 += 1; im_f101000 = _more_stokes.arS[ofst101000] + re_f100100 = _more_stokes.arS[ofst100100]#; ofst100100 += 1; im_f100100 = _more_stokes.arS[ofst100100] + re_f100010 = _more_stokes.arS[ofst100010]#; ofst100010 += 1; im_f100010 = _more_stokes.arS[ofst100010] + re_f100001 = _more_stokes.arS[ofst100001]#; ofst100001 += 1; im_f100001 = _more_stokes.arS[ofst100001] + + re_f011000 = _more_stokes.arS[ofst011000]#; ofst011000 += 1; im_f011000 = _more_stokes.arS[ofst011000] + re_f010100 = _more_stokes.arS[ofst010100]#; ofst010100 += 1; im_f010100 = _more_stokes.arS[ofst010100] + re_f010010 = _more_stokes.arS[ofst010010]#; ofst010010 += 1; im_f010010 = _more_stokes.arS[ofst010010] + re_f010001 = _more_stokes.arS[ofst010001]#; ofst010001 += 1; im_f010001 = _more_stokes.arS[ofst010001] + + re_f001100 = _more_stokes.arS[ofst001100]#; ofst001100 += 1; im_f001100 = _more_stokes.arS[ofst001100] + re_f001010 = _more_stokes.arS[ofst001010]#; ofst001010 += 1; im_f001010 = _more_stokes.arS[ofst001010] + re_f001001 = _more_stokes.arS[ofst001001]#; ofst001001 += 1; im_f001001 = _more_stokes.arS[ofst001001] + + re_f000110 = _more_stokes.arS[ofst000110]#; ofst000110 += 1; im_f000110 = _more_stokes.arS[ofst000110] + re_f000101 = _more_stokes.arS[ofst000101]#; ofst000101 += 1; im_f000101 = _more_stokes.arS[ofst000101] + + re_f000011 = _more_stokes.arS[ofst000011]#; ofst000011 += 1; im_f000011 = _more_stokes.arS[ofst000011] + + re_a100000 = re_f100000 - re_a000000#; im_a100000 = im_f100000 - im_a000000 + re_a010000 = re_f010000 - re_a000000#; im_a010000 = im_f010000 - im_a000000 + re_a001000 = re_f001000 - re_a000000#; im_a001000 = im_f001000 - im_a000000 + re_a000100 = re_f000100 - re_a000000#; im_a000100 = im_f000100 - im_a000000 + re_a000010 = re_f000010 - re_a000000#; im_a000010 = im_f000010 - im_a000000 + re_a000001 = re_f000001 - re_a000000#; im_a000001 = im_f000001 - im_a000000 + re_a110000 = re_a000000 - re_f010000 - re_f100000 + re_f110000#; im_a110000 = im_a000000 - im_f010000 - im_f100000 + im_f110000 + re_a101000 = re_a000000 - re_f001000 - re_f100000 + re_f101000#; im_a101000 = im_a000000 - im_f001000 - im_f100000 + im_f101000 + re_a100100 = re_a000000 - re_f000100 - re_f100000 + re_f100100#; im_a100100 = im_a000000 - im_f000100 - im_f100000 + im_f100100 + re_a100010 = re_a000000 - re_f000010 - re_f100000 + re_f100010#; im_a100010 = im_a000000 - im_f000010 - im_f100000 + im_f100010 + re_a100001 = re_a000000 - re_f000001 - re_f100000 + re_f100001#; im_a100001 = im_a000000 - im_f000001 - im_f100000 + im_f100001 + re_a011000 = re_a000000 - re_f001000 - re_f010000 + re_f011000#; im_a011000 = im_a000000 - im_f001000 - im_f010000 + im_f011000 + re_a010100 = re_a000000 - re_f000100 - re_f010000 + re_f010100#; im_a010100 = im_a000000 - im_f000100 - im_f010000 + im_f010100 + re_a010010 = re_a000000 - re_f000010 - re_f010000 + re_f010010#; im_a010010 = im_a000000 - im_f000010 - im_f010000 + im_f010010 + re_a010001 = re_a000000 - re_f000001 - re_f010000 + re_f010001#; im_a010001 = im_a000000 - im_f000001 - im_f010000 + im_f010001 + re_a001100 = re_a000000 - re_f000100 - re_f001000 + re_f001100#; im_a001100 = im_a000000 - im_f000100 - im_f001000 + im_f001100 + re_a001010 = re_a000000 - re_f000010 - re_f001000 + re_f001010#; im_a001010 = im_a000000 - im_f000010 - im_f001000 + im_f001010 + re_a001001 = re_a000000 - re_f000001 - re_f001000 + re_f001001#; im_a001001 = im_a000000 - im_f000001 - im_f001000 + im_f001001 + re_a000110 = re_a000000 - re_f000010 - re_f000100 + re_f000110#; im_a000110 = im_a000000 - im_f000010 - im_f000100 + im_f000110 + re_a000101 = re_a000000 - re_f000001 - re_f000100 + re_f000101#; im_a000101 = im_a000000 - im_f000001 - im_f000100 + im_f000101 + re_a000011 = re_a000000 - re_f000001 - re_f000010 + re_f000011#; im_a000011 = im_a000000 - im_f000001 - im_f000010 + im_f000011 + + reI2 = (re_a100000 + re_a110000*re2 + (re_a101000 + re_a100100)*rx2 + (re_a100010 + re_a100001)*ry2)*re2 + reI2 += (re_a010000 + (re_a011000 + re_a010100)*rx2 + (re_a010010 + re_a010001)*ry2)*re2 + reI2 += (re_a001000 + re_a001100*rx2 + (re_a001010 + re_a001001)*ry2)*rx2 + reI2 += (re_a000100 + (re_a000110 + re_a000101)*ry2)*rx2 + (re_a000010 + re_a000011*ry2)*ry2 + re_a000001*ry2 + re_a000000 + #imI2 = (im_a100000 + im_a110000*re2 + (im_a101000 + im_a100100)*rx2 + (im_a100010 + im_a100001)*ry2)*re2 + #imI2 += (im_a010000 + (im_a011000 + im_a010100)*rx2 + (im_a010010 + im_a010001)*ry2)*re2 + #imI2 += (im_a001000 + im_a001100*rx2 + (im_a001010 + im_a001001)*ry2)*rx2 + #imI2 += (im_a000100 + (im_a000110 + im_a000101)*ry2)*rx2 + (im_a000010 + im_a000011*ry2)*ry2 + im_a000001*ry2 + im_a000000 + #OC05052018: Note that this does not include all terms of multi-dim "bi-linear" interpolation!? + + resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + else: + resDegCoh[resOfst] = 0 + else: + ie1_0 = ie + ie2_0 = iep + ie1_0_origPerE = ie1_0*origPerE + ie2_0_origPerEp = ie2_0*origPerEp + ie2_0_origPerEp_p_ie1_0_origPerE = ie2_0_origPerEp + ie1_0_origPerE + ie1_0_origPerEp_p_ie1_0_origPerE = ie1_0*origPerEp + ie1_0_origPerE + ie2_0_origPerEp_p_ie2_0_origPerE = ie2_0_origPerEp + ie2_0*origPerE + + ofstMI = ie2_0_origPerEp_p_ie1_0_origPerE + ix2_0*origPerXp + ix1_0*origPerX + iy2_0*origPerYp + iy1_0*origPerY + ofstI1 = ie1_0_origPerEp_p_ie1_0_origPerE + ix1_0*origPerXp + ix1_0*origPerX + iy1_0*origPerYp + iy1_0*origPerY + ofstI2 = ie2_0_origPerEp_p_ie2_0_origPerE + ix2_0*origPerXp + ix2_0*origPerX + iy2_0*origPerYp + iy2_0*origPerY + + reMI = self.arS[ofstMI]; imMI = self.arS[ofstMI + 1] + absMI = sqrt(reMI*reMI + imMI*imMI) + reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] + reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] + resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + + resOfst += 1 + resEp += resEstep + resE += resEstep + resXp += resXstep + resX += resXstep + resYp += resYstep + resY += resYstep + + return resDegCoh + +#**************************************************************************** +class SRWLWfr(object): + """Radiation Wavefront (Electric Field)""" + #arEx = 0 #array('f', [0]*2) #horizontal complex electric field component array; NOTE: only 'f' (float) is supported for the moment (Jan. 2011) + #arEy = 0 #array('f', [0]*2) #vertical complex electric field component array + #mesh = SRWLRadMesh() + #Rx = 0 #instant wavefront radii + #Ry = 0 + #dRx = 0 #error of wavefront radii + #dRy = 0 + #xc = 0 #instant transverse coordinates of wavefront instant "source center" + #yc = 0 + #avgPhotEn = 0 #average photon energy for time-domain simulations + #presCA = 0 #presentation/domain: 0- coordinates, 1- angles + #presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + #numTypeElFld = 'f' #electric field numerical type: 'f' (float) or 'd' (double) + #unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) + #partBeam = SRWLPartBeam() #particle beam source; strictly speaking, it should be just SRWLParticle; however, "multi-electron" information can appear useful for those cases when "multi-electron intensity" can be deduced from the "single-electron" one by convolution + #arElecPropMatr = array('d', [0]*20) #effective 1st order "propagation matrix" for electron beam parameters + #arMomX = array('d', [0]*11) #statistical moments (of Wigner distribution); to check the exact number of moments required + #arMomY = array('d', [0]*11) + #arWfrAuxData = array('d', [0]*30) #array of auxiliary wavefront data + + def __init__(self, _arEx=None, _arEy=None, _typeE='f', _eStart=0, _eFin=0, _ne=0, _xStart=0, _xFin=0, _nx=0, _yStart=0, _yFin=0, _ny=0, _zStart=0, _partBeam=None): + """ + :param _arEx: horizontal complex electric field component array; NOTE: only 'f' (float) is supported for the moment (Jan. 2011) + :param _arEy: vertical complex electric field component array + :param _typeE: electric field numerical type: 'f' (float) or 'd' (double) + :param _eStart: initial value of photon energy (/time) + :param _eFin: final value of photon energy (/time) + :param _ne: numbers of points vs photon energy + :param _xStart: initial value of horizontal positions + :param _xFin: final value of horizontal positions + :param _nx: numbers of points vs horizontal positions + :param _yStart: initial vertical positions + :param _yFin: final value of vertical positions + :param _ny: numbers of points vs vertical positions + :param _zStart: longitudinal position + :param _partBeam: particle beam source; strictly speaking, it should be just SRWLParticle; however, "multi-electron" information can appear useful for those cases when "multi-electron intensity" can be deduced from the "single-electron" one by convolution + + Some additional parameters, that are not included in constructor arguments: + Rx, Ry: instant wavefront radii + dRx, dRy: error of wavefront radii + xc, yc: transverse coordinates of wavefront instant "source center" + avgPhotEn: average photon energy for time-domain simulations + presCA: presentation/domain: 0- coordinates, 1- angles + presFT: presentation/domain: 0- frequency (photon energy), 1- time + unitElFld: electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2) + arElecPropMatr: effective 1st order "propagation matrix" for electron beam parameters + arMomX, arMomY: statistical moments (of Wigner distribution); to check the exact number of moments required + arWfrAuxData: array of auxiliary wavefront data + """ + self.arEx = _arEx + self.arEy = _arEy + #self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _xStart, _xFin, _nx, _yStart, _yFin, _ny) + self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _xStart, _xFin, _nx, _yStart, _yFin, _ny, _zStart) + self.numTypeElFld = _typeE + self.partBeam = SRWLPartBeam() if _partBeam is None else _partBeam + + self.Rx = 0 #instant wavefront radii + self.Ry = 0 + self.dRx = 0 #error of wavefront radii + self.dRy = 0 + self.xc = 0 #instant transverse coordinates of wavefront instant "source center" + self.yc = 0 + self.avgPhotEn = 0 #average photon energy for time-domain simulations + self.presCA = 0 #presentation/domain: 0- coordinates, 1- angles + self.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + self.unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) ? + self.unitElFldAng = 0 #electric field units in angular representation: 0- sqrt(Wavelength[m]*Phot/s/0.1%bw/mrad^2) vs rad/Wavelength[m], 1- sqrt(Phot/s/0.1%bw/mrad^2) vs rad; [Phot/s/0.1%bw] can be replaced by [J/eV] or [W], depending on self.unitElFld, self.presFT and self.presCA + self.arElecPropMatr = array('d', [0] * 20) #effective 1st order "propagation matrix" for electron beam parameters + self.arMomX = array('d', [0] * 11 * _ne) #statistical moments (of Wigner distribution); to check the exact number of moments required + self.arMomY = array('d', [0] * 11 * _ne) + self.arWfrAuxData = array('d', [0] * 30) #array of auxiliary wavefront data + + nProd = _ne * _nx * _ny #array length to store one component of complex electric field + EXNeeded = 0 + EYNeeded = 0 + if(_arEx == 1) and (nProd > 0): + EXNeeded = 1 + if(_arEy == 1) and (nProd > 0): + EYNeeded = 1 + if(EXNeeded > 0) or (EYNeeded > 0): + self.allocate(_ne, _nx, _ny, EXNeeded, EYNeeded) + + #def allocate(self, _ne, _nx, _ny, EXNeeded=1, EYNeeded=1, typeE='f'): + def allocate(self, _ne, _nx, _ny, _EXNeeded=1, _EYNeeded=1, _typeE='f', _backupNeeded=0): #OC141115 + """Allocate Electric Field data + :param _ne: number of points vs photon energy / time + :param _nx: number of points vs horizontal position / angle + :param _ny: number of points vs vertical position / angle + :param _EXNeeded: switch specifying whether Ex data is necessary or not (1 or 0) + :param _EYNeeded: switch specifying whether Ey data is necessary or not (1 or 0) + :param _typeE: numerical type of Electric Field data: float (single precision) or double ('f' or 'd'); double is not yet supported + :param _backupNeeded: switch specifying whether backup of Electric Field data (arExAux, arEyAux) should be created or not (1 or 0) + """ + #print('') #debugging + #print(' (re-)allocating: old point numbers: ne=',self.mesh.ne,' nx=',self.mesh.nx,' ny=',self.mesh.ny) #,' type:',self.numTypeElFld) + #print(' new point numbers: ne=',_ne,' nx=',_nx,' ny=',_ny) #,' type:',typeE) + #print(' backupNeeded',_backupNeeded) + + nTot = 2*_ne*_nx*_ny #array length to store one component of complex electric field + nMom = 11*_ne + if _EXNeeded: + #print(' trying to (re-)allocate Ex ... ', end='') + #del self.arEx + if _backupNeeded: #OC141115 + self.arExAux = self.arEx + #print(' self.arExAux assigned') #debugging + #else: + # del self.arEx + #self.arEx = array(typeE, [0]*nTot) + self.arEx = srwl_uti_array_alloc(_typeE, nTot) + #print(' done') + if len(self.arMomX) != nMom: + del self.arMomX + self.arMomX = array('d', [0]*nMom) + if _EYNeeded: + #print(' trying to (re-)allocate Ey ... ', end='') + #del self.arEy + if _backupNeeded: #OC141115 + self.arEyAux = self.arEy + #print(' self.arEyAux assigned') #debugging + #else: + # del self.arEy + #self.arEy = array(typeE, [0]*nTot) + self.arEy = srwl_uti_array_alloc(_typeE, nTot) + #print(' done') + if len(self.arMomY) != nMom: + del self.arMomY + self.arMomY = array('d', [0]*nMom) + self.numTypeElFld = _typeE + self.mesh.ne = _ne + self.mesh.nx = _nx + self.mesh.ny = _ny + + def delE(self, _type=0, _treatEX=1, _treatEY=1): #OC151115 + """Delete Electric Field data + :param _type: type of data to be deleted: 0- arEx, arEy, arExAux, arEyAux; 1- arEx, arEy only; 2- arExAux, arEyAux only + :param _treatEX: switch specifying whether Ex data should be deleted or not (1 or 0) + :param _treatEY: switch specifying whether Ey data should be deleted or not (1 or 0) + """ + if _treatEX: + if((_type == 0) or (_type == 1)): + if(self.arEx is not None): + del self.arEx; self.arEx = None + if((_type == 0) or (_type == 2)): + if(hasattr(self, 'arExAux')): + if(self.arExAux is not None): + del self.arExAux; self.arExAux = None + if _treatEY: + if((_type == 0) or (_type == 1)): + if(self.arEy is not None): + del self.arEy; self.arEy = None + if((_type == 0) or (_type == 2)): + if(hasattr(self, 'arEyAux')): + if(self.arEyAux is not None): + del self.arEyAux; self.arEyAux = None + + def addE(self, _wfr, _meth=0): + """Add Another Electric Field Wavefront + :param _wfr: wavefront to be added + :param _meth: method of adding the wavefront _wfr: + 0- simple addition assuming _wfr to have same mesh as this wavefront + 1- add using bilinear interpolation (taking into account meshes of the two wavefronts) + 2- add using bi-quadratic interpolation (taking into account meshes of the two wavefronts) + 3- add using bi-cubic interpolation (taking into account meshes of the two wavefronts) + """ + if(_meth == 0): + if((self.mesh.ne != _wfr.mesh.ne) or (self.mesh.nx != _wfr.mesh.nx) or (self.mesh.ny != _wfr.mesh.ny)): + raise Exception("Electric Field addition can not be performed by this method because of unequal sizes of the two Wavefronts") + nTot = 2*self.mesh.ne*self.mesh.nx*self.mesh.ny + #test: + #aux = 0 + wfr_arEx = _wfr.arEx + wfr_arEy = _wfr.arEy + + for i in range(nTot): + #for some reason, this increases memory requirements in Py: + self.arEx[i] += wfr_arEx[i] + self.arEy[i] += wfr_arEy[i] + + elif(_meth == 1): + #to implement + raise Exception("This Electric Field addition method is not implemented yet") + + elif(_meth == 2): + #to implement + raise Exception("This Electric Field addition method is not implemented yet") + + elif(_meth == 3): + #to implement + raise Exception("This Electric Field addition method is not implemented yet") + + def copy_comp(self, _stokes): + """Copy compenents of Electric Field to Stokes structure""" + if(isinstance(_stokes, SRWLStokes) == False): + raise Exception("Incorrect Stokes parameters object submitted") + nTot = self.mesh.ne*self.mesh.nx*self.mesh.ny + nTotSt = nTot*4 + nTot2 = nTot*2 + nTot3 = nTot*3 + if(_stokes.arS is not None): + if(len(_stokes.arS) < nTotSt): + _stokes.arS = array('f', [0]*nTotSt) + else: + _stokes.arS = array('f', [0]*nTotSt) + for i in range(nTot): + i2 = i*2 + i2p1 = i2 + 1 + #reEx = self.arEx[i2] + #imEx = self.arEx[i2p1] + #reEy = self.arEy[i2] + #imEy = self.arEy[i2p1] + _stokes.arS[i] = self.arEx[i2] #reEx + _stokes.arS[i + nTot] = self.arEx[i2p1] #imEx + _stokes.arS[i + nTot2] = self.arEy[i2] #reEy + _stokes.arS[i + nTot3] = self.arEy[i2p1] #imEy + _stokes.mesh.set_from_other(self.mesh) + + def calc_stokes(self, _stokes, _n_stokes_comp=4): #OC04052018 + #def calc_stokes(self, _stokes): + """Calculate Stokes parameters from Electric Field""" + if(_stokes.mutual <= 0): + nTot = self.mesh.ne*self.mesh.nx*self.mesh.ny + #if(type(_stokes).__name__ != 'SRWLStokes')): + if(isinstance(_stokes, SRWLStokes) == False): + raise Exception("Incorrect Stokes parameters object submitted") + nTotSt = nTot*4 + nTot2 = nTot*2 + nTot3 = nTot*3 + if(_stokes.arS is not None): + if(len(_stokes.arS) < nTotSt): + _stokes.arS = array('f', [0]*nTotSt) + else: + _stokes.arS = array('f', [0]*nTotSt) + for i in range(nTot): + i2 = i*2 + i2p1 = i2 + 1 + reEx = self.arEx[i2] + imEx = self.arEx[i2p1] + reEy = self.arEy[i2] + imEy = self.arEy[i2p1] + intLinX = reEx*reEx + imEx*imEx + intLinY = reEy*reEy + imEy*imEy + _stokes.arS[i] = intLinX + intLinY + #_stokes.arS[i + nTot] = intLinX - intLinY + if(_n_stokes_comp > 1): _stokes.arS[i + nTot] = intLinX - intLinY #OC04052018 + #_stokes.arS[i + nTot2] = -2*(reEx*reEy + imEx*imEy) #check sign + if(_n_stokes_comp > 2): _stokes.arS[i + nTot2] = 2*(reEx*reEy + imEx*imEy) #OC04052018 #check sign (in SRW for Igor: -2*(ReEX*ReEZ + ImEX*ImEZ)) + #_stokes.arS[i + nTot3] = 2*(-reEx*reEy + imEx*imEy) #check sign + if(_n_stokes_comp > 3): _stokes.arS[i + nTot3] = 2*(reEx*imEy - imEx*reEy) #OC04052018 #check sign (in SRW for Igor: 2*(-ReEX*ImEZ + ImEX*ReEZ)) + + #DEBUG + #if(isnan(reEx) or isnan(imEx) or isnan(reEy) or isnan(imEy)): + # print('reEx=', reEx, ' imEx=', imEx, ' reEy=', reEy, ' imEy=', imEy) + #END DEBUG + + _stokes.mesh.set_from_other(self.mesh) + #Why this is using self.mesh, whereas if(_stokes.mutual) uses _stokes.mesh? Consider correcting. + + else: #calculate Mutual Stokes parameters on the _stokes.mesh + yNpRes = _stokes.mesh.ny + yStartRes = _stokes.mesh.yStart + yStepRes = 0 + if(yNpRes > 1): yStepRes = (_stokes.mesh.yFin - yStartRes)/(yNpRes - 1) + + xNpRes = _stokes.mesh.nx + xStartRes = _stokes.mesh.xStart + xStepRes = 0 + if(xNpRes > 1): xStepRes = (_stokes.mesh.xFin - xStartRes)/(xNpRes - 1) + + eNpRes = _stokes.mesh.ne + eStartRes = _stokes.mesh.eStart + eStepRes = 0 + if(eNpRes > 1): eStepRes = (_stokes.mesh.eFin - eStartRes)/(eNpRes - 1) + + nTot = eNpRes*xNpRes*yNpRes #OC06052018 (uncommented) + #nTot = 2*eNpRes*xNpRes*yNpRes #OC04052018 (since and other Stokes may be complex entities) + + #nTot1 = nTot*nTot + nTot1 = 2*nTot*nTot #OC06052018 + nTot2 = nTot1*2 + nTot3 = nTot1*3 + + yNpWfr = self.mesh.ny + yStartWfr = self.mesh.yStart + yStepWfr = 0 + if(yNpWfr > 1): yStepWfr = (self.mesh.yFin - yStartWfr)/(yNpWfr - 1) + yNpWfr_mi_1 = yNpWfr - 1 + + xNpWfr = self.mesh.nx + xStartWfr = self.mesh.xStart + xStepWfr = 0 + if(xNpWfr > 1): xStepWfr = (self.mesh.xFin - xStartWfr)/(xNpWfr - 1) + xNpWfr_mi_1 = xNpWfr - 1 + + eNpWfr = self.mesh.ne + eStartWfr = self.mesh.eStart + eStepWfr = 0 + if(eNpWfr > 1): eStepWfr = (self.mesh.eFin - eStartWfr)/(eNpWfr - 1) + eNpWfr_mi_1 = eNpWfr - 1 + + perE = 2 + perX = perE*eNpWfr + perY = perX*xNpWfr + + perXr = perE*eNpRes + perYr = perX*xNpRes + + nTotAux = nTot*2 + auxArEx = array('f', [0]*nTotAux) #OC06052018 + auxArEy = array('f', [0]*nTotAux) + #auxArEx = array('f', [0]*nTot) #OC04052018 (since may be a complex entity) + #auxArEy = array('f', [0]*nTot) + + #print(perE, perX, perY) + + #ir = 0 + yRes = yStartRes + for iy in range(yNpRes): + iyWfr0 = 0 + if(yStepWfr > 0): iyWfr0 = int(trunc((yRes - yStartWfr)/yStepWfr + 1.e-09)) + if((iyWfr0 < 0) or (iyWfr0 > yNpWfr_mi_1)): + #_stokes.arS[ir] = 0; _stokes.arS[ir + nTot1] = 0; _stokes.arS[ir + nTot2] = 0; _stokes.arS[ir + nTot3] = 0; + #ir += 1; + yRes += yStepRes + continue + iyWfr1 = iyWfr0 + 1 + if(iyWfr1 > yNpWfr_mi_1): iyWfr1 = yNpWfr_mi_1 + ty = 0 + if(yStepWfr > 0): ty = (yRes - (yStartWfr + yStepWfr*iyWfr0))/yStepWfr + + iy0_perY = iyWfr0*perY + iy1_perY = iyWfr1*perY + iy_perYr = iy*perYr + + xRes = xStartRes + for ix in range(xNpRes): + ixWfr0 = 0 + if(xStepWfr > 0): ixWfr0 = int(trunc((xRes - xStartWfr)/xStepWfr + 1.e-09)) + if((ixWfr0 < 0) or (ixWfr0 > xNpWfr_mi_1)): + #_stokes.arS[ir] = 0; _stokes.arS[ir + nTot1] = 0; _stokes.arS[ir + nTot2] = 0; _stokes.arS[ir + nTot3] = 0; + #ir += 1; + xRes += xStepRes + continue + ixWfr1 = ixWfr0 + 1 + if(ixWfr1 > xNpWfr_mi_1): ixWfr1 = xNpWfr_mi_1 + tx = 0 + if(xStepWfr > 0): tx = (xRes - (xStartWfr + xStepWfr*ixWfr0))/xStepWfr + + ix0_perX = ixWfr0*perX + ix1_perX = ixWfr1*perX + ix_perXr = ix*perXr + + eRes = eStartRes + for ie in range(eNpRes): + ieWfr0 = 0 + if(eStepWfr > 0): ieWfr0 = int(trunc((eRes - eStartWfr)/eStepWfr + 1.e-09)) + if((ieWfr0 < 0) or (ieWfr0 > eNpWfr_mi_1)): + #_stokes.arS[ir] = 0; _stokes.arS[ir + nTot1] = 0; _stokes.arS[ir + nTot2] = 0; _stokes.arS[ir + nTot3] = 0; + #ir += 1; + eRes += eStepRes + continue + ieWfr1 = ieWfr0 + 1 + if(ieWfr1 > eNpWfr_mi_1): ieWfr1 = eNpWfr_mi_1 + te = 0 + if(eStepWfr > 0): te = (eRes - (eStartWfr + eStepWfr*ieWfr0))/eStepWfr + + ie0_perE = ieWfr0*perE + ie1_perE = ieWfr1*perE + ie_perE = ie*perE + + ofstR = ie_perE + ix_perXr + iy_perYr + + ofst000 = ie0_perE + ix0_perX + iy0_perY + ofst100 = ie1_perE + ix0_perX + iy0_perY + ofst010 = ie0_perE + ix1_perX + iy0_perY + ofst001 = ie0_perE + ix0_perX + iy1_perY + ofst110 = ie1_perE + ix1_perX + iy0_perY + ofst101 = ie1_perE + ix0_perX + iy1_perY + ofst011 = ie0_perE + ix1_perX + iy1_perY + ofst111 = ie1_perE + ix1_perX + iy1_perY + + a000 = self.arEx[ofst000]#; print(a000) + f100 = self.arEx[ofst100] + f010 = self.arEx[ofst010] + f001 = self.arEx[ofst001] + f110 = self.arEx[ofst110] + f101 = self.arEx[ofst101] + f011 = self.arEx[ofst011] + f111 = self.arEx[ofst111] + a100 = f100 - a000 + a010 = f010 - a000 + a001 = f001 - a000 + a110 = a000 - f010 - f100 + f110 + a101 = a000 - f001 - f100 + f101 + a011 = a000 - f001 - f010 + f011 + a111 = f001 + f010 - f011 + f100 - f101 - f110 + f111 - a000 + #auxArEx[ir] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + auxArEx[ofstR] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + + a000 = self.arEx[ofst000 + 1] + f100 = self.arEx[ofst100 + 1] + f010 = self.arEx[ofst010 + 1] + f001 = self.arEx[ofst001 + 1] + f110 = self.arEx[ofst110 + 1] + f101 = self.arEx[ofst101 + 1] + f011 = self.arEx[ofst011 + 1] + f111 = self.arEx[ofst111 + 1] + a100 = f100 - a000 + a010 = f010 - a000 + a001 = f001 - a000 + a110 = a000 - f010 - f100 + f110 + a101 = a000 - f001 - f100 + f101 + a011 = a000 - f001 - f010 + f011 + a111 = f001 + f010 - f011 + f100 - f101 - f110 + f111 - a000 + #auxArEx[ir + 1] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + auxArEx[ofstR + 1] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + + a000 = self.arEy[ofst000] + f100 = self.arEy[ofst100] + f010 = self.arEy[ofst010] + f001 = self.arEy[ofst001] + f110 = self.arEy[ofst110] + f101 = self.arEy[ofst101] + f011 = self.arEy[ofst011] + f111 = self.arEy[ofst111] + a100 = f100 - a000 + a010 = f010 - a000 + a001 = f001 - a000 + a110 = a000 - f010 - f100 + f110 + a101 = a000 - f001 - f100 + f101 + a011 = a000 - f001 - f010 + f011 + a111 = f001 + f010 - f011 + f100 - f101 - f110 + f111 - a000 + #auxArEy[ir] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + auxArEy[ofstR] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + + a000 = self.arEy[ofst000 + 1] + f100 = self.arEy[ofst100 + 1] + f010 = self.arEy[ofst010 + 1] + f001 = self.arEy[ofst001 + 1] + f110 = self.arEy[ofst110 + 1] + f101 = self.arEy[ofst101 + 1] + f011 = self.arEy[ofst011 + 1] + f111 = self.arEy[ofst111 + 1] + a100 = f100 - a000 + a010 = f010 - a000 + a001 = f001 - a000 + a110 = a000 - f010 - f100 + f110 + a101 = a000 - f001 - f100 + f101 + a011 = a000 - f001 - f010 + f011 + a111 = f001 + f010 - f011 + f100 - f101 - f110 + f111 - a000 + #auxArEy[ir + 1] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + auxArEy[ofstR + 1] = a000 + (a100 + (a110 + a111*ty)*tx + a101*ty)*te + (a010 + a011*ty)*tx + a001*ty + + #ir += 2 + eRes += eStepRes + xRes += xStepRes + yRes += yStepRes + + #DEBUG + #print('SRWLWfr::calc_stokes: eNpRes=', eNpRes, ' xNpRes=', xNpRes, ' yNpRes=', yNpRes) + #print(' nTot=', nTot, ' nTot1=', nTot1, ' nTot2=', nTot2, ' nTot3=', nTot3) + #END DEBUG + + perX = perE*eNpRes + perY = perX*xNpRes + ir = 0 + for iy in range(yNpRes): + iy_perY = iy*perY + for iyp in range(yNpRes): + iyp_perY = iyp*perY + for ix in range(xNpRes): + ix_perX = ix*perX + ix_perX_p_iy_perY = ix_perX + iy_perY + for ixp in range(xNpRes): + ixp_perX = ixp*perX + ixp_perX_p_iyp_perY = ixp_perX + iyp_perY + for ie in range(eNpRes): + ie_perE = ie*perE + ie_perE_p_ix_perX_p_iy_perY = ie_perE + ix_perX_p_iy_perY + reEx = auxArEx[ie_perE_p_ix_perX_p_iy_perY] + imEx = auxArEx[ie_perE_p_ix_perX_p_iy_perY + 1] + reEy = auxArEy[ie_perE_p_ix_perX_p_iy_perY] + imEy = auxArEy[ie_perE_p_ix_perX_p_iy_perY + 1] + for iep in range(eNpRes): + iep_perE = iep*perE + iep_perE_p_ixp_perX_p_iyp_perY = iep_perE + ixp_perX_p_iyp_perY + reExT = auxArEx[iep_perE_p_ixp_perX_p_iyp_perY] + imExT = auxArEx[iep_perE_p_ixp_perX_p_iyp_perY + 1] + reEyT = auxArEy[iep_perE_p_ixp_perX_p_iyp_perY] + imEyT = auxArEy[iep_perE_p_ixp_perX_p_iyp_perY + 1] + + #OC04052018 (commented-out) + #intLinX = reEx*reExT + imEx*imExT + #intLinY = reEy*reEyT + imEy*imEyT #; print(intLinX, intLinY) + #_stokes.arS[ir] = intLinX + intLinY + #_stokes.arS[ir + nTot1] = intLinX - intLinY #check sign + #_stokes.arS[ir + nTot2] = -reEx*reEyT - reExT*reEy - imEx*imEyT - imExT*imEy #-2*(reEx*reEy + imEx*imEy) #check sign + #_stokes.arS[ir + nTot3] = -reEx*reEyT - reExT*reEy + imEx*imEyT + imExT*imEy #2*(-reEx*reEy + imEx*imEy) #check sign + + #OC04052018 + reMI_s0_X = reEx*reExT + imEx*imExT + reMI_s0_Y = reEy*reEyT + imEy*imEyT + imMI_s0_X = imEx*reExT - reEx*imExT + imMI_s0_Y = imEy*reEyT - reEy*imEyT + _stokes.arS[ir] = reMI_s0_X + reMI_s0_Y #Re(s0) + ir_p_1 = ir + 1 + _stokes.arS[ir_p_1] = imMI_s0_X + imMI_s0_Y #Im(s0) + if(_n_stokes_comp > 1): + _stokes.arS[ir + nTot1] = reMI_s0_X - reMI_s0_Y #Re(s1), see MutualStokes.nb and LectureNotes notebook + _stokes.arS[ir_p_1 + nTot1] = imMI_s0_X - imMI_s0_Y #Im(s1) + if(_n_stokes_comp > 2): + #DEBUG + #print(' ir + nTot2=', ir + nTot2) + #END DEBUG + _stokes.arS[ir + nTot2] = imExT*imEy + imEx*imEyT + reExT*reEy + reEx*reEyT #Re(s2) + _stokes.arS[ir_p_1 + nTot2] = imEy*reExT - imEyT*reEx - imExT*reEy + imEx*reEyT #Im(s2) + if(_n_stokes_comp > 3): + _stokes.arS[ir + nTot3] = imEyT*reEx + imEy*reExT - imExT*reEy - imEx*reEyT #Re(s3) + _stokes.arS[ir_p_1 + nTot3] = imEx*imEyT - imExT*imEy - reExT*reEy + reEx*reEyT #Im(s3) + + #ir += 1 + ir += 2 #OC04052018 (since and other Stokes are complex entities) + del auxArEx + del auxArEy + +#**************************************************************************** +class SRWLOpt(object): + """Optical Element (base class)""" + +class SRWLOptD(SRWLOpt): + """Optical Element: Drift Space""" + + def __init__(self, _L=0, _treat=0): + """ + :param _L: Length [m] + :param _treat: switch specifying whether the absolute optical path should be taken into account in radiation phase (=1) or not (=0, default) + """ + self.L = _L + self.treat = _treat + +class SRWLOptA(SRWLOpt): + """Optical Element: Aperture / Obstacle""" + + def __init__(self, _shape='r', _ap_or_ob='a', _Dx=0, _Dy=0, _x=0, _y=0): + """ + :param _shape: 'r' for rectangular, 'c' for circular :param _ap_or_ob: 'a' for aperture, 'o' for obstacle :param _Dx: horizontal transverse dimension [m]; in case of circular aperture, only Dx is used for diameter :param _Dy: vertical transverse dimension [m]; in case of circular aperture, Dy is ignored :param _x: horizontal transverse coordinate of center [m] :param _y: vertical transverse coordinate of center [m] """ - self.shape = _shape #'r' for rectangular, 'c' for circular - self.ap_or_ob = _ap_or_ob #'a' for aperture, 'o' for obstacle - self.Dx = _Dx #transverse dimensions [m]; in case of circular aperture, only Dx is used for diameter - self.Dy = _Dy - self.x = _x #transverse coordinates of center [m] - self.y = _y + self.shape = _shape #'r' for rectangular, 'c' for circular + self.ap_or_ob = _ap_or_ob #'a' for aperture, 'o' for obstacle + self.Dx = _Dx #transverse dimensions [m]; in case of circular aperture, only Dx is used for diameter + self.Dy = _Dy + self.x = _x #transverse coordinates of center [m] + self.y = _y + +class SRWLOptL(SRWLOpt): + """Optical Element: Thin Lens""" + + def __init__(self, _Fx=1e+23, _Fy=1e+23, _x=0, _y=0): + """ + :param _Fx: focal length in horizontal plane [m] + :param _Fy: focal length in vertical plane [m] + :param _x: horizontal coordinate of center [m] + :param _y: vertical coordinate of center [m] + """ + self.Fx = _Fx #focal lengths [m] + self.Fy = _Fy + self.x = _x #transverse coordinates of center [m] + self.y = _y + +class SRWLOptAng(SRWLOpt): + """Optical Element: Angle""" + + def __init__(self, _ang_x=0, _ang_y=0): + """ + :param _ang_x: horizontal angle [rad] + :param _ang_y: vertical angle [rad] + """ + self.AngX = _ang_x + self.AngY = _ang_y + +class SRWLOptShift(SRWLOpt): + """Optical Element: Shirt""" + + def __init__(self, _shift_x=0, _shift_y=0): + """ + :param _shift_x: horizontal shift [m] + :param _shift_y: vertical shift [m] + """ + self.ShiftX = _shift_x + self.ShiftY = _shift_y + +class SRWLOptZP(SRWLOpt): + """Optical Element: Thin Lens""" + + def __init__(self, _nZones=100, _rn=0.1e-03, _thick=10e-06, _delta1=1e-06, _atLen1=0.1, _delta2=0, _atLen2=1e-06, _x=0, _y=0): + """ + :param _nZones: total number of zones + :param _rn: auter zone radius [m] + :param _thick: thickness [m] + :param _delta1: refractuve index decrement of the "main" material + :param _atLen1: attenuation length [m] of the "main" material + :param _delta2: refractuve index decrement of the "complementary" material + :param _atLen2: attenuation length [m] of the "complementary" material + :param _x: horizontal transverse coordinate of center [m] + :param _y: vertical transverse coordinates of center [m] + """ + self.nZones = _nZones #total number of zones + self.rn = _rn #auter zone radius [m] + self.thick = _thick #thickness [m] + self.delta1 = _delta1 #refractuve index decrement of the "main" material + self.delta2 = _delta2 #refractuve index decrement of the "complementary" material + self.atLen1 = _atLen1 #attenuation length [m] of the "main" material + self.atLen2 = _atLen2 #attenuation length [m] of the "complementary" material + self.x = _x #transverse coordinates of center [m] + self.y = _y + +class SRWLOptWG(SRWLOpt): + """Optical Element: Waveguide""" + + def __init__(self, _L=1, _Dx=10e-03, _Dy=10e-03, _x=0, _y=0): + """ + :param _L: length [m] + :param _Dx: horizontal transverse dimension [m] + :param _Dy: vertical transverse dimension [m] + :param _x: horizontal transverse coordinate of center [m] + :param _y: vertical transverse coordinate of center [m] + """ + self.L = _L #length [m] + self.Dx = _Dx #transverse dimensions [m] + self.Dy = _Dy + self.x = _x #transverse coordinates of center [m] + self.y = _y + +class SRWLOptT(SRWLOpt): + """Optical Element: Transmission (generic)""" + + def __init__(self, _nx=1, _ny=1, _rx=1e-03, _ry=1e-03, _arTr=None, _extTr=0, _Fx=1e+23, _Fy=1e+23, _x=0, _y=0, _ne=1, _eStart=0, _eFin=0): + """ + :param _nx: number of transmission data points in the horizontal direction + :param _ny: number of transmission data points in the vertical direction + :param _rx: range of the horizontal coordinate [m] for which the transmission is defined + :param _ry: range of the vertical coordinate [m] for which the transmission is defined + :param _arTr: complex C-aligned data array (of 2*ne*nx*ny length) storing amplitude transmission and optical path difference as function of transverse coordinates + :param _extTr: transmission outside the grid/mesh is zero (0), or it is same as on boundary (1) + :param _Fx: estimated focal length in the horizontal plane [m] + :param _Fy: estimated focal length in the vertical plane [m] + :param _x: horizontal transverse coordinate of center [m] + :param _y: vertical transverse coordinate of center [m] + :param _ne: number of transmission data points vs photon energy + :param _eStart: initial value of photon energy + :param _eFin: final value of photon energy + """ + + self.arTr = _arTr #complex C-aligned data array (of 2*ne*nx*ny length) storing amplitude transmission and optical path difference as function of transverse position + if((_arTr is None) or ((len(_arTr) != _ne*_nx*_ny*2) and (_ne*_nx*_ny > 0))): + self.allocate(_ne, _nx, _ny) + + #self.ne = _ne #number of transmission data points vs photon energy + #self.nx = _nx #numbers of transmission data points in the horizontal and vertical directions + #self.ny = _ny + #self.eStart = _eStart #initial and final values of photon energy + #self.eFin = _eFin + #self.rx = _rx #ranges of horizontal and vertical coordinates [m] for which the transmission is defined + #self.ry = _ry + + halfRangeX = 0.5*_rx; + halfRangeY = 0.5*_ry; + self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _x - halfRangeX, _x + halfRangeX, _nx, _y - halfRangeY, _y + halfRangeY, _ny) + + self.extTr = _extTr #0- transmission outside the grid/mesh is zero; 1- it is same as on boundary + self.Fx = _Fx #estimated focal lengths [m] + self.Fy = _Fy + + #self.x = _x #transverse coordinates of center [m] + #self.y = _y + #if _ne > 1: _Fx, _Fy should be arrays vs photon energy? + + def allocate(self, _ne, _nx, _ny): + #self.ne = _ne + #self.nx = _nx + #self.ny = _ny + + if(hasattr(self, 'mesh')): + self.mesh.ne = _ne + self.mesh.nx = _nx + self.mesh.ny = _ny + else: + self.mesh = SRWLRadMesh(0, 0, _ne, 0, 0, _nx, 0, 0, _ny) + + nTot = 2*_ne*_nx*_ny #total array length to store amplitude transmission and optical path difference + self.arTr = array('d', [0]*nTot) + + def get_data(self, _typ, _dep=3, _e=0, _x=0, _y=0): + """Returns Transmission Data Characteristic + :param _typ: type of transmission characteristic to extract: 1- amplitude transmission, 2- intensity transmission, 3- optical path difference + :param _dep: type of dependence to extract: 0- vs photon energy, 1- vs horizontal position, 2- vs vertical position, 3- vs hor. & vert. positions + :param _e: photon energy [eV] (to keep fixed) + :param _x: horizontal position [m] (to keep fixed) + :param _y: vertical position [m] (to keep fixed) + """ + nTot = self.mesh.ne*self.mesh.nx*self.mesh.ny + arAux = array('d', [0]*nTot) + for i in range(nTot): #put all data into one column using "C-alignment" as a "flat" 1D array + tr = 0 + if((_typ == 1) or (_typ == 2)): #amplitude or intensity transmission + tr = self.arTr[i*2] + if(_typ == 2): #intensity transmission + tr *= tr + else: #optical path difference + tr = self.arTr[i*2 + 1] + arAux[i] = tr + if (_dep == 3) and (self.mesh.ne == 1): return arAux + #print('total extract passed') + + arOut = None + xStep = 0 + if self.mesh.nx > 1: xStep = (self.mesh.xFin - self.mesh.xStart)/(self.mesh.nx - 1) + yStep = 0 + if self.mesh.ny > 1: yStep = (self.mesh.yFin - self.mesh.yStart)/(self.mesh.ny - 1) + inperpOrd = 1 #inperpolation order, up to 3 + if _dep == 0: #dependence vs photon energy + arOut = array('d', [0]*self.mesh.ne) + for ie in range(self.mesh.ne): + #arOut[ie] = srwl_uti_interp_2d(_x, _y, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + arOut[ie] = uti_math.interp_2d(_x, _y, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + else: + ie = 0 + if self.mesh.ne > 1: + if _e >= self.mesh.eFin: ie = self.mesh.ne - 1 + elif _e > self.mesh.eStart: + eStep = (self.mesh.eFin - self.mesh.eStart)/(self.mesh.ne - 1) + ie = int(round((_e - self.mesh.eStart)/eStep)) + #print(ie) + if _dep == 1: #dependence vs horizontal position + arOut = array('d', [0]*self.mesh.nx) + xx = self.mesh.xStart + for ix in range(self.mesh.nx): + #arOut[ix] = srwl_uti_interp_2d(xx, _y, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + arOut[ix] = uti_math.interp_2d(xx, _y, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + xx += xStep + elif _dep == 2: #dependence vs vertical position + arOut = array('d', [0]*self.mesh.ny) + yy = self.mesh.yStart + for iy in range(self.mesh.ny): + #arOut[iy] = srwl_uti_interp_2d(_x, yy, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + arOut[iy] = uti_math.interp_2d(_x, yy, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + yy += yStep + elif _dep == 3: #dependence vs horizontal and vertical position + nTot = self.mesh.nx*self.mesh.ny + arOut = array('d', [0]*nTot) + yy = self.mesh.yStart + i = 0 + for iy in range(self.mesh.ny): + xx = self.mesh.xStart + for ix in range(self.mesh.nx): + #arOut[i] = srwl_uti_interp_2d(xx, yy, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + arOut[i] = uti_math.interp_2d(xx, yy, self.mesh.xStart, xStep, self.mesh.nx, self.mesh.yStart, yStep, self.mesh.ny, arAux, inperpOrd, self.mesh.ne, ie) + i += 1 + xx += xStep + yy += yStep + del arAux + #print(len(arOut)) + return arOut + +class SRWLOptMir(SRWLOpt): + """Optical Element: Mirror (focusing)""" + + def set_dim_sim_meth(self, _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0): + """Sets Mirror Dimensions, Aperture Shape and its simulation method + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) + :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + """ + if((_sim_meth < 1) or (_sim_meth > 2)): + raise Exception("Simulation method is not specified correctly (should be 1 for \"thin\", 2 for \"thick\" element approximation)") + self.dt = _size_tang + self.ds = _size_sag + self.apShape = _ap_shape + self.meth = _sim_meth + self.npt = _npt + self.nps = _nps + self.treatInOut = _treat_in_out + self.extIn = _ext_in + self.extOut = _ext_out + self.Fx = 0 #i.e. focal lengthes are not set + self.Fy = 0 + + def set_reflect(self, _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=0, _ph_en_fin=0, _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + """Sets Mirror Reflectivity + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat array complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + nTot = int(_n_ph_en*_n_ang*_n_comp*2) + if(nTot < 2): + raise Exception("Incorrect Reflectivity array parameters") + _n_comp = int(_n_comp) + if((_n_comp < 1) or (_n_comp > 2)): + raise Exception("Number of reflectivity coefficient components can be 1 or 2") + + if(not(isinstance(_refl, list) or isinstance(_refl, array))): + self.arRefl = array('d', [_refl]*nTot) + for i in range(int(round(nTot/2))): + i2 = i*2 + self.arRefl[i2] = _refl + self.arRefl[i2 + 1] = 0 + else: + self.arRefl = _refl + + #DEBUG + #print(self.arRefl) + + self.reflNumPhEn = int(_n_ph_en) + self.reflNumAng = int(_n_ang) + self.reflNumComp = _n_comp + self.reflPhEnStart = _ph_en_start + self.reflPhEnFin = _ph_en_fin + self.reflPhEnScaleType = _ph_en_scale_type + self.reflAngStart = _ang_start + self.reflAngFin = _ang_fin + self.reflAngScaleType = _ang_scale_type + + def set_orient(self, _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0): + """Defines Mirror Orientation in the frame of the incident photon beam + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + """ + self.nvx = _nvx + self.nvy = _nvy + self.nvz = _nvz + self.tvx = _tvx + self.tvy = _tvy + self.x = _x + self.y = _y + self.Fx = 0 #i.e. focal lengths are not set + self.Fy = 0 + + def set_all(self, + _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=100, _nps=100, _treat_in_out=1, _ext_in=0, _ext_out=0, + _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, + _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + """ + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after that the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + + self.set_dim_sim_meth(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out) + self.set_orient(_nvx, _nvy, _nvz, _tvx, _tvy, _x, _y) + self.set_reflect(_refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + +class SRWLOptMirPl(SRWLOptMir): + """Optical Element: Mirror: Plane""" + + def __init__(self, + _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=100, _nps=100, _treat_in_out=1, _ext_in=0, _ext_out=0, + _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, + _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + """ + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after that the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + #There are no other members, except for those of the base class. + #Finishing of the mirror setup requires calling these 3 functions (with their required arguments): + #self.set_dim_sim_meth(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out) + #self.set_orient(_nvx, _nvy, _nvz, _tvx, _tvy, _x, _y) + #self.set_reflect(_refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + self.set_all(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out, + _nvx, _nvy, _nvz, _tvx, _tvy, _x, _y, + _refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + +class SRWLOptMirEl(SRWLOptMir): + """Optical Element: Mirror: Elliptical + NOTE: in the Local frame of the Mirror tangential direction is X, saggital Y, mirror normal is along Z""" + + def __init__(self, _p=1, _q=1, _ang_graz=1e-03, _r_sag=1.e+23, + _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0, + _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, + _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + """ + :param _p: distance from first focus (\"source\") to mirror center [m] + :param _q: distance from mirror center to second focus (\"image\") [m] + :param _ang_graz: grazing angle at mirror center at perfect orientation [rad] + :param _r_sag: sagital radius of curvature at mirror center [m] + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) + :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + + self.p = _p + self.q = _q + self.angGraz = _ang_graz + self.radSag = _r_sag + + #finishing of the mirror setup requires calling these 3 functions (with their required arguments): + #self.set_dim_sim_meth(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out) + #self.set_orient(_nvx, _nvy, _nvz, _tvx, _tvy, _x, _y) + #self.set_reflect(_refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + self.set_all(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out, + _nvx, _nvy, _nvz, _tvx, _tvy, _x, _y, + _refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + +class SRWLOptMirSph(SRWLOptMir): + """Optical Element: Mirror: Spherical""" + + def __init__(self, _r=1., + _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0, + _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, + _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + """ + :param _r: radius of surface curvature [m] + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) + :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + + self.rad = _r + + #finishing of the mirror setup requires calling these 3 functions (with their required arguments): + self.set_all(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out, + _nvx, _nvy, _nvz, _tvx, _tvy, _x, _y, + _refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + +class SRWLOptMirTor(SRWLOptMir): + """Optical Element: Mirror: Toroid + NOTE: in the Local frame of the Mirror tangential direction is X, saggital Y, mirror normal is along Z""" + + def __init__(self, _rt=1, _rs=1, + _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0, + _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, + _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): + + """ + :param _rt: tangential (major) radius [m] + :param _rs: sagittal (minor) radius [m] + :param _size_tang: size in tangential direction [m] + :param _size_sag: size in sagital direction [m] + :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) + :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) + :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) + :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) + :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: + 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; + 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; + 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; + :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters + :param _nvx: horizontal coordinate of central normal vector + :param _nvy: vertical coordinate of central normal vector + :param _nvz: longitudinal coordinate of central normal vector + :param _tvx: horizontal coordinate of central tangential vector + :param _tvy: vertical coordinate of central tangential vector + :param _x: horizontal position of mirror center [m] + :param _y: vertical position of mirror center [m] + :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) + :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified + :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified + :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) + :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified + :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified + :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) + :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified + :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified + :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) + """ + + self.radTan = _rt + self.radSag = _rs + + #finishing of the mirror setup requires calling these 3 functions (with their required arguments): + self.set_all(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out, + _nvx, _nvy, _nvz, _tvx, _tvy, _x, _y, + _refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + +class SRWLOptG(SRWLOpt): + """Optical Element: Grating""" + + def __init__(self, _mirSub, _m=1, _grDen=100, _grDen1=0, _grDen2=0, _grDen3=0, _grDen4=0, _grAng=0): + """ + :param _mirSub: SRWLOptMir (or derived) type object defining substrate of the grating + :param _m: output (diffraction) order + :param _grDen: groove density [lines/mm] (coefficient a0 in the polynomial groove density: a0 + a1*y + a2*y^2 + a3*y^3 + a4*y^4) + :param _grDen1: groove density polynomial coefficient a1 [lines/mm^2] + :param _grDen2: groove density polynomial coefficient a2 [lines/mm^3] + :param _grDen3: groove density polynomial coefficient a3 [lines/mm^4] + :param _grDen4: groove density polynomial coefficient a4 [lines/mm^5] + :param _grAng: angle between the grove direction and the saggital direction of the substrate [rad] (by default, groves are made along saggital direction (_grAng=0)) + """ + + if(isinstance(_mirSub, SRWLOptMir) == False): + raise Exception("Incorrect substrate data submitted to Grating constructor(SRWLOptMir type object is expected for the substrate)") + + self.mirSub = _mirSub #SRWLOptMir (or derived) type object defining the Grating substrate + self.m = _m #output order + self.grDen = _grDen #grove density [lines/mm] (polynomial coefficient a0 in: a0 + a1*y + a2*y^2 + a3*y^3 + a4*y^4) + self.grDen1 = _grDen1 #grove density polynomial coefficient a1 in [lines/mm^2] + self.grDen2 = _grDen2 #grove density polynomial coefficient a2 in [lines/mm^3] + self.grDen3 = _grDen3 #grove density polynomial coefficient a3 in [lines/mm^4] + self.grDen4 = _grDen4 #grove density polynomial coefficient a4 in [lines/mm^5] + self.grAng = _grAng #angle between the grove direction and the saggital direction of the substrate [rad] + +class SRWLOptCryst(SRWLOpt): + """Optical Element: Ideal Crystal""" + + #def _init_(self, _d_space, _psiOr, _psiOi, _psiHr, _psiHi, _psiHBr, _psiHBi, _H1, _H2, _H3, _Tc, _Tasym, _nx, _ny, _nz, _sx, _sy, _sz, _aChi, _aPsi, _aThe): + #def __init__(self, _d_sp, _psi0r, _psi0i, _psi_hr, _psi_hi, _psi_hbr, _psi_hbi, _h1, _h2, _h3, _tc, _ang_as, _nvx, _nvy, _nvz, _tvx, _tvy): + #def __init__(self, _d_sp, _psi0r, _psi0i, _psi_hr, _psi_hi, _psi_hbr, _psi_hbi, _tc, _ang_as, _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0): + def __init__(self, _d_sp, _psi0r, _psi0i, _psi_hr, _psi_hi, _psi_hbr, _psi_hbi, _tc, _ang_as, _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _uc=1): + """ + :param _d_sp: (_d_space) crystal reflecting planes d-spacing (John's dA) [A] + :param _psi0r: real part of 0-th Fourier component of crystal polarizability (John's psi0c.real) (units?) + :param _psi0i: imaginary part of 0-th Fourier component of crystal polarizability (John's psi0c.imag) (units?) + :param _psi_hr: (_psiHr) real part of H-th Fourier component of crystal polarizability (John's psihc.real) (units?) + :param _psi_hi: (_psiHi) imaginary part of H-th Fourier component of crystal polarizability (John's psihc.imag) (units?) + :param _psi_hbr: (_psiHBr:) real part of -H-th Fourier component of crystal polarizability (John's psimhc.real) (units?) + :param _psi_hbi: (_psiHBi:) imaginary part of -H-th Fourier component of crystal polarizability (John's psimhc.imag) (units?) + :param _tc: crystal thickness [m] (John's thicum) + :param _ang_as: (_Tasym) asymmetry angle [rad] (John's alphdg) + :param _nvx: horizontal coordinate of outward normal to crystal surface (John's angles: thdg, chidg, phidg) + :param _nvy: vertical coordinate of outward normal to crystal surface (John's angles: thdg, chidg, phidg) + :param _nvz: longitudinal coordinate of outward normal to crystal surface (John's angles: thdg, chidg, phidg) + :param _tvx: horizontal coordinate of central tangential vector (John's angles: thdg, chidg, phidg) + :param _tvy: vertical coordinate of central tangential vector (John's angles: thdg, chidg, phidg) + :param _uc: crystal use case: 1- Bragg Reflection, 2- Bragg Transmission (Laue cases to be added) + """ + #""" + #The Miller Inices are removed from this input (after discussion with A. Suvorov), because _d_sp already incorporates this information: + #:param _h1: 1st index of diffraction vector (John's hMilND) + #:param _h2: 2nd index of diffraction vector (John's kMilND) + #:param _h3: 3rd index of diffraction vector (John's lMilND) + #However, a member-function may be added here to calculate _d_sp from teh Miller Indices and material constant(s) + + #Moved to Propagation Parameters + #:param _sx: horizontal coordinate of optical axis after crystal [m] (John's) + #:param _sy: vertical coordinate of optical axis after crystal [m] (John's) + #:param _sz: longitudinal coordinate of optical axis after crystal [m] (John's) + + #to go to member functions (convenience derived parameters) + #:param _aChi: crystal roll angle (John's) + #:param _aPsi: crystal yaw angle (John's) + #:param _aThe: crystal theta angle (John's) + #""" + self.dSp = _d_sp + self.psi0r = _psi0r + self.psi0i = _psi0i + self.psiHr = _psi_hr + self.psiHi = _psi_hi + self.psiHbr = _psi_hbr + self.psiHbi = _psi_hbi + #self.h1 = _h1 + #self.h2 = _h2 + #self.h3 = _h3 + self.tc = _tc + self.angAs = _ang_as + self.nvx = _nvx + self.nvy = _nvy + self.nvz = _nvz + self.tvx = _tvx + self.tvy = _tvy + + self.aux_energy = None #MR01082016: renamed self.energy to self.aux_energy. + self.aux_ang_dif_pl = None #MR01082016: renamed self.ang_dif_pl to self.aux_ang_dif_pl. + + self.uc = _uc #OC04092016 + + def set_orient(self, _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0): + """Defines Crystal Orientation in the frame of the Incident Photon beam + :param _nvx: horizontal coordinate of normal vector + :param _nvy: vertical coordinate of normal vector + :param _nvz: longitudinal coordinate of normal vector + :param _tvx: horizontal coordinate of tangential vector + :param _tvy: vertical coordinate of tangential vector + """ + self.nvx = _nvx + self.nvy = _nvy + self.nvz = _nvz + self.tvx = _tvx + self.tvy = _tvy + + def find_orient(self, _en, _ang_dif_pl=0): + """Finds optimal crystal orientation in the input beam frame (i.e. surface normal and tangential vectors) and the orientation of the output beam frame (i.e. coordinates of the longitudinal and horizontal vectors in the input beam frame) + :param _en: photon energy [eV] + :param _ang_dif_pl: diffraction plane angle (0 corresponds to the vertical deflection; pi/2 to the horizontal deflection; any value in between is allowed) + :return: list of two triplets of vectors: + out[0] is the list of 3 base vectors [tangential, saggital, normal] defining the crystal orientation + out[1] is the list of 3 base vectors [ex, ey, ez] defining orientation of the output beam frame + the cartesian coordinates of all these vectors are given in the frame of the input beam + """ + + self.aux_energy = _en #MR01082016: renamed self.energy to self.aux_energy. + self.aux_ang_dif_pl = _ang_dif_pl #MR01082016: renamed self.ang_dif_pl to self.aux_ang_dif_pl. + + #dSi = 5.43096890 # Si lattice constant (A) + eV2wA = 12398.4193009 # energy to wavelength conversion factor 12398.41930092394 + wA = eV2wA/_en + #Tar = math.pi*Ta/180. + #Kh = norm(Hr)/dSi # reflection vector modulus + kh = 1./self.dSp # because self.dSp = dSi/norm(Hr) + hv = [0, kh*cos(self.angAs), -kh*sin(self.angAs)] + tBr = asin(wA*kh/2) + tKin = tBr - self.angAs # TKin = Tbr - Tar + tKou = tBr + self.angAs # TKou = Tbr + Tar + abs_c0 = sqrt(self.psi0r*self.psi0r + self.psi0i*self.psi0i) + #dTref = abs(c0)*(1+math.sin(TKou)/math.sin(TKin))/2/math.sin(2*Tbr) + dTref = 0.5*abs_c0*(1 + sin(tKou)/sin(tKin))/sin(2*tBr) + tIn = tKin + dTref + + def prodV(_a, _b): + return [_a[1]*_b[2] - _a[2]*_b[1], _a[2]*_b[0] - _a[0]*_b[2], _a[0]*_b[1] - _a[1]*_b[0]] + + def prodMV(_m, _v): + return [_m[0][0]*_v[0] + _m[0][1]*_v[1] + _m[0][2]*_v[2], + _m[1][0]*_v[0] + _m[1][1]*_v[1] + _m[1][2]*_v[2], + _m[2][0]*_v[0] + _m[2][1]*_v[1] + _m[2][2]*_v[2]] + + def normV(_a): + return sqrt(sum(n**2 for n in _a)) + + #Crystal orientation vectors + nv = [0, cos(tIn), -sin(tIn)] + tv = [0, sin(tIn), cos(tIn)] + sv = prodV(nv, tv) + + mc = [[sv[0], nv[0], tv[0]], + [sv[1], nv[1], tv[1]], + [sv[2], nv[2], tv[2]]] + + #Diffracted beam frame vectors + z1c = [sv[2], sqrt(1. - sv[2]**2 - (tv[2] + wA*hv[2])**2), tv[2] + wA*hv[2]] + #rz = [sv[0]*z1c[0] + nv[0]*z1c[1] + tv[0]*z1c[2], + # sv[1]*z1c[0] + nv[1]*z1c[1] + tv[1]*z1c[2], + # sv[2]*z1c[0] + nv[2]*z1c[1] + tv[2]*z1c[2]] + rz = prodMV(mc, z1c) + + x1c = prodV(hv, z1c) + if sum(n**2 for n in x1c) == 0: + x1c = prodV(nv, z1c) + if sum(n**2 for n in x1c) == 0: + x1c = sv + x1c = [n/normV(x1c) for n in x1c] + + #rx = [sv[0]*x1c[0] + nv[0]*x1c[1] + tv[0]*x1c[2], + # sv[1]*x1c[0] + nv[1]*x1c[1] + tv[1]*x1c[2], + # sv[2]*x1c[0] + nv[2]*x1c[1] + tv[2]*x1c[2]] + rx = prodMV(mc, x1c) + ry = prodV(rz, rx) + #print('ex0=',rx, 'ey0=',ry, 'ez0=',rz) + + #OC06092016 + tvNew = None; svNew = None; nvNew = None + ex = None; ey = None; ez = None + + #The following corresponds to Bragg case (Reflection and Transmission) + tolAng = 1.e-06 + if(abs(_ang_dif_pl) < tolAng): #case of the vertical deflection plane + #return [[tv, sv, nv], [rx, ry, rz]] + tvNew = tv; svNew = sv; nvNew = nv + ex = rx; ey = ry; ez = rz + + else: #case of a tilted deflection plane + cosA = cos(_ang_dif_pl) + sinA = sin(_ang_dif_pl) + mr = [[cosA, -sinA, 0], + [sinA, cosA, 0], + [0, 0, 1]] + + ez = prodMV(mr, rz) + + #Selecting "Horizontal" and "Vertical" directions of the Output beam frame + #trying to use "minimum deviation" from the corresponding "Horizontal" and "Vertical" directions of the Input beam frame + ezIn = [0, 0, 1] + e1 = prodV(ez, ezIn) + abs_e1x = abs(e1[0]) + abs_e1y = abs(e1[1]) + + #ex = None; ey = None + if(abs_e1x >= abs_e1y): + if(e1[0] > 0): ex = e1 + else: ex = [-e1[0], -e1[1], -e1[2]] + ex = [n/normV(ex) for n in ex] + ey = prodV(ez, ex) + else: + if(e1[1] > 0): ey = e1 + else: ey = [-e1[0], -e1[1], -e1[2]] + ey = [n/normV(ey) for n in ey] + ex = prodV(ey, ez) + #return [[prodMV(mr, tv), prodMV(mr, sv), prodMV(mr, nv)], [ex, ey, ez]] + tvNew = prodMV(mr, tv) #OC06092016 + svNew = prodMV(mr, sv) + nvNew = prodMV(mr, nv) + + #OC06092016 + if(self.uc == 2): #Bragg Transmission + ex = [1, 0, 0] + ey = [0, 1, 0] + ez = [0, 0, 1] + #To check this and implement other self.uc cases! + + return [[tvNew, svNew, nvNew], [ex, ey, ez]] + +class SRWLOptC(SRWLOpt): + """Optical Element: Container""" + + def __init__(self, _arOpt=None, _arProp=None): + """ + :param _arOpt: optical element structures list (or array) + :param _arProp: list of lists of propagation parameters to be used for each individual optical element + Each element _arProp[i] is a list in which elements mean: + [0]: Auto-Resize (1) or not (0) Before propagation + [1]: Auto-Resize (1) or not (0) After propagation + [2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) + [3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation + [4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) + [5]: Horizontal Range modification factor at Resizing (1. means no modification) + [6]: Horizontal Resolution modification factor at Resizing (1. means no modification) + [7]: Vertical Range modification factor at Resizing (1. means no modification) + [8]: Vertical Resolution modification factor at Resizing (1. means no modification) + [9]: Optional: Type of wavefront Shift before Resizing (vs which coordinates; to be implemented) + [10]: Optional: New Horizontal wavefront Center position after Shift (to be implemented) + [11]: Optional: New Vertical wavefront Center position after Shift (to be implemented) + [12]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Horizontal Coordinate + [13]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Vertical Coordinate + [14]: Optional: Orientation of the Output Optical Axis vector in the Incident Beam Frame: Longitudinal Coordinate + [15]: Optional: Orientation of the Horizontal Base vector of the Output Frame in the Incident Beam Frame: Horizontal Coordinate + [16]: Optional: Orientation of the Horizontal Base vector of the Output Frame in the Incident Beam Frame: Vertical Coordinate + """ + self.arOpt = _arOpt #optical element structures array + if(_arOpt is None): + self.arOpt = [] + self.arProp = _arProp #list of lists of propagation parameters to be used for individual optical elements + if(_arProp is None): + self.arProp = [] + + def allocate(self, _nElem): + self.arOpt = [SRWLOpt()]*_nElem + self.arProp = [[0]*17]*_nElem + + def append_drift(self, _len): #OC28042018 + """Appends drift space to the end of the Container + :param _len: length [m] + """ + + if(_len == 0.): return + + nOE = len(self.arOpt) + lastOptEl = self.arOpt[nOE - 1] + + if(isinstance(lastOptEl, SRWLOptD)): #just change the length of the last drift + lastOptEl.L += _len + #print('Drift length updated to:', lastOptEl.L) + else: + self.arOpt.append(SRWLOptD(_len)) + ppDr = [0, 0, 1.0, 1, 0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] #to improve + nPP = len(self.arProp) + nOE += 1 + if(nOE == nPP): + ppPost = copy(self.arProp[nPP - 1]) + self.arProp[nPP - 1] = ppDr + self.arProp.append(ppPost) + elif(nOE > nPP): + self.arProp.append(ppDr) + + +#**************************************************************************** +#**************************************************************************** +#Setup some transmission-type optical elements +#**************************************************************************** +#**************************************************************************** +#def srwl_opt_setup_CRL(_foc_plane, _delta, _atten_len, _shape, _apert_h, _apert_v, _r_min, _n, _wall_thick, _xc, _yc, _void_cen_rad=None, _e_start=0, _e_fin=0, _nx=1001, _ny=1001): +def srwl_opt_setup_CRL(_foc_plane, _delta, _atten_len, _shape, _apert_h, _apert_v, _r_min, _n, _wall_thick, _xc, _yc, _void_cen_rad=None, _e_start=0, _e_fin=0, _nx=1001, _ny=1001, _ang_rot_ex=0, _ang_rot_ey=0): #, _ang_rot_ez=0): #OC15042018 + """ + Setup Transmission type Optical Element which simulates Compound Refractive Lens (CRL) + :param _foc_plane: plane of focusing: 1- horizontal, 2- vertical, 3- both + :param _delta: refractive index decrement (can be one number of array vs photon energy) + :param _atten_len: attenuation length [m] (can be one number of array vs photon energy) + :param _shape: 1- parabolic, 2- circular (spherical) + :param _apert_h: horizontal aperture size [m] + :param _apert_v: vertical aperture size [m] + :param _r_min: radius (on tip of parabola for parabolic shape) [m] + :param _n: number of lenses (/"holes") + :param _wall_thick: min. wall thickness between "holes" [m] + :param _xc: horizontal coordinate of center [m] + :param _yc: vertical coordinate of center [m] + :param _void_cen_rad: flat array/list of void center coordinates and radii: [x1, y1, r1, x2, y2, r2,...] + :param _e_start: initial photon energy + :param _e_fin: final photon energy + :param _nx: number of points vs horizontal position to represent the transmission element + :param _ny: number of points vs vertical position to represent the transmission element + :param _ang_rot_ex: angle [rad] of CRL rotation about horizontal axis + :param _ang_rot_ey: angle [rad] of CRL rotation about vertical axis + :param _ang_rot_ez: angle [rad] of CRL rotation about longitudinal axis + :return: transmission (SRWLOptT) type optical element which simulates CRL + """ + + input_parms = { #MR26022016: Added all input parameters to include in return object: + "type": "crl", + "focalPlane": _foc_plane, + "refractiveIndex": _delta, + "attenuationLength": _atten_len, + "shape": _shape, + "horizontalApertureSize": _apert_h, + "verticalApertureSize": _apert_v, + "radius": _r_min, + "numberOfLenses": _n, + "wallThickness": _wall_thick, + "horizontalCenterCoordinate": _xc, + "verticalCenterCoordinate": _yc, + "voidCenterCoordinates": _void_cen_rad, + "initialPhotonEnergy": _e_start, + "finalPhotonPnergy": _e_fin, + "horizontalPoints": _nx, + "verticalPoints": _ny, + } + + def ray_path_in_one_CRL(_x, _y, _foc_plane, _shape, _half_apert, _r_min, _wall_thick): #CRL is always centered + rE2 = 0 + if((_foc_plane == 1) or (_foc_plane == 3)): #focusing in horizontal plane + rE2 += _x*_x + if((_foc_plane == 2) or (_foc_plane == 3)): #focusing in vertical or in both planes + rE2 += _y*_y + + halfApE2 = _half_apert*_half_apert + + sectLen = 0 + if(_shape == 1): #parabolic + a = 1./_r_min + sectLen = _wall_thick + a*halfApE2 + if(rE2 < halfApE2): + return _wall_thick + a*rE2 + elif(_shape == 2): #circular (or spherical) + radE2 = _r_min*_r_min + sectLen = _wall_thick + 2*_r_min + if(_half_apert < _r_min): + sectLen = _wall_thick + 2*(_r_min - sqrt(radE2 - halfApE2)) + if(rE2 < halfApE2): + #return sectLen - 2*sqrt(radE2 - rE2) + return _wall_thick + 2*(_r_min - sqrt(radE2 - rE2)) #OC22042018 + elif(rE2 < radE2): + return sectLen - 2*sqrt(radE2 - rE2) + + return sectLen + + #OC20042018 + def ray_path_in_one_CRL_rot(_x, _y, _foc_plane, _shape, _half_apert, _r_min, _wall_thick, _kx, _ky): #CRL is centered, but rotated about vert. / hor axes + rE2 = 0 + if((_foc_plane == 1) or (_foc_plane == 3)): #focusing in horizontal plane + rE2 += _x*_x + if((_foc_plane == 2) or (_foc_plane == 3)): #focusing in vertical or in both planes + rE2 += _y*_y + + halfApE2 = _half_apert*_half_apert + + kx2 = _kx*_kx + ky2 = _ky*_ky + tiltFact = sqrt(1. + kx2 + ky2) + sectLen = 0 + if(_shape == 1): #parabolic + a = 1./_r_min + sectLen = (_wall_thick + a*halfApE2)*tiltFact + if(rE2 < halfApE2): + if(_foc_plane == 1): + if(_kx == 0): return (_wall_thick + a*rE2)*tiltFact + else: + a_kx = a*_kx + a_kx2 = a_kx*_kx + a_kx2_w = a_kx2*_wall_thick + two_a_kx_x = 2*a_kx*_x + return tiltFact*(2 - sqrt(1 - a_kx2_w + two_a_kx_x) - sqrt(1 - a_kx2_w - two_a_kx_x))/a_kx2 + elif(_foc_plane == 2): + if(_ky == 0): return (_wall_thick + a*rE2)*tiltFact + else: + a_ky = a*_ky + a_ky2 = a_ky*_ky + a_ky2_w = a_ky2*_wall_thick + two_a_ky_y = 2*a_ky*_y + return tiltFact*(2 - sqrt(1 - a_ky2_w + two_a_ky_y) - sqrt(1 - a_ky2_w - two_a_ky_y))/a_ky2 + else: + a_k2 = a*(kx2 + ky2) + buf0 = _ky*_x - _kx*_y + buf1 = 1 - a*a*buf0*buf0 - w*a_k2 + buf2 = 2*a*(_kx*_x + _ky*_y) + return tiltFact*(2 - sqrt(buf1 - buf2) - sqrt(buf1 + buf2))/a_k2 + + elif(_shape == 2): #circular (or spherical) + + #This takes into account circular CRL tilt / rotation only approximately! + radE2 = _r_min*_r_min + sectLen = (_wall_thick + 2*_r_min)*tiltFact + + if(_half_apert < _r_min): + sectLen = _wall_thick + 2*(_r_min - sqrt(radE2 - halfApE2)) + if(rE2 < halfApE2): + #return sectLen - 2*sqrt(radE2 - rE2) + return (_wall_thick + 2*(_r_min - sqrt(radE2 - rE2)))*tiltFact #OC22042018 + + elif(rE2 < radE2): + return (sectLen - 2*sqrt(radE2 - rE2))*tiltFact + + #return sectLen + return sectLen*tiltFact + + def ray_path_in_spheres(_x, _y, _void_cen_rad): + n = int(round(len(_void_cen_rad)/3)) + sumPath = 0. + for i in range(n): + i3 = i*3 + dx = _x - _void_cen_rad[i3] + dy = _y - _void_cen_rad[i3 + 1] + rVoid = _void_cen_rad[i3 + 2] + uE2 = dx*dx + dy*dy + rVoidE2 = rVoid*rVoid + if(uE2 < rVoidE2): + sumPath += 2*sqrt(rVoidE2 - uE2) + #print('Void crossed:', dx, dy, rVoid, sumPath) + return sumPath + + #foc_len = (0.5*_r_min/(_n*_delta)) + #print('Optical Element Setup: CRL Focal Length:', foc_len, 'm') + + #fx = 1e+23 + #fy = 1e+23 + #if(_foc_plane != 1): + # fy = foc_len + #if(_foc_plane != 2): + # fx = foc_len + + rx = _apert_h*1.1 + ry = _apert_v*1.1 + nx = _nx #1001 + ny = _ny #1001 + ne = 1 + arDelta = [0] + arAttenLen = [0] + + #if(((type(_delta).__name__ == 'list') or (type(_delta).__name__ == 'array')) and ((type(_atten_len).__name__ == 'list') or (type(_atten_len).__name__ == 'array'))): + if(isinstance(_delta, list) or isinstance(_delta, array)) and (isinstance(_atten_len, list) or isinstance(_atten_len, array)): + ne = len(_delta) + ne1 = len(_atten_len) + if(ne > ne1): + ne = ne1 + arDelta = _delta + arAttenLen = _atten_len + else: + arDelta[0] = _delta + arAttenLen[0] = _atten_len -class SRWLOptL(SRWLOpt): - """Optical Element: Thin Lens""" - - def __init__(self, _Fx=1e+23, _Fy=1e+23, _x=0, _y=0): - """ - :param _Fx: focal length in horizontal plane [m] - :param _Fy: focal length in vertical plane [m] - :param _x: horizontal coordinate of center [m] - :param _y: vertical coordinate of center [m] - """ - self.Fx = _Fx #focal lengths [m] - self.Fy = _Fy - self.x = _x #transverse coordinates of center [m] - self.y = _y + trM = None #OC15042018 + vZero = [0,0,0] + if(_ang_rot_ex != 0): + trRot = uti_math.trf_rotation([1,0,0], _ang_rot_ex, vZero) + trM = trRot[0] + if(_ang_rot_ey != 0): + trRot = uti_math.trf_rotation([0,1,0], _ang_rot_ey, vZero) + if(trM is not None): trM = uti_math.matr_prod(trRot[0], trM) + else: trM = trRot[0] + + kxRay = 0; kyRay = 0 + #cosecAngX = 1; cosecAngY = 1 + #fact_f = 1 + fact_opt_path = 1 + kTol = 1.e-07 #to tune + if(trM is not None): + trMi = uti_math.matr_3x3_inv(trM) + vRay = uti_math.matr_prod(trMi, [0,0,1]) + kxRay = vRay[0]/vRay[2] + if(abs(kxRay) < kTol): kxRay = 0 + kyRay = vRay[1]/vRay[2] + if(abs(kyRay) < kTol): kyRay = 0 -class SRWLOptZP(SRWLOpt): - """Optical Element: Thin Lens""" + fact_opt_path = sqrt(1. + kxRay*kxRay + kyRay*kyRay) #optical path factor (due to CRL rotations) + + #if(kxRay != 0): cosecAngX = 1/vRay[0] + #if(kyRay != 0): cosecAngY = 1/vRay[1] + #fact_f = 1./sqrt(1. + kxRay*kxRay + kyRay*kyRay) #focal length factor (due to CRL rotations) + + #foc_len = 0.5*_r_min/(_n*arDelta[int(0.5*ne)]) + foc_len = 0.5*_r_min/(_n*arDelta[int(0.5*ne)]*fact_opt_path) #OC19042018 + print('Optical Element Setup: CRL Focal Length:', foc_len, 'm') + + fx = 1e+23 + fy = 1e+23 + if(_foc_plane != 1): + fy = foc_len + if(_foc_plane != 2): + fx = foc_len - def __init__(self, _nZones=100, _rn=0.1e-03, _thick=10e-06, _delta1=1e-06, _atLen1=0.1, _delta2=0, _atLen2=1e-06, _x=0, _y=0): - """ - :param _nZones: total number of zones - :param _rn: auter zone radius [m] - :param _thick: thickness [m] - :param _delta1: refractuve index decrement of the "main" material - :param _atLen1: attenuation length [m] of the "main" material - :param _delta2: refractuve index decrement of the "complementary" material - :param _atLen2: attenuation length [m] of the "complementary" material - :param _x: horizontal transverse coordinate of center [m] - :param _y: vertical transverse coordinates of center [m] - """ - self.nZones = _nZones #total number of zones - self.rn = _rn #auter zone radius [m] - self.thick = _thick #thickness [m] - self.delta1 = _delta1 #refractuve index decrement of the "main" material - self.delta2 = _delta2 #refractuve index decrement of the "complementary" material - self.atLen1 = _atLen1 #attenuation length [m] of the "main" material - self.atLen2 = _atLen2 #attenuation length [m] of the "complementary" material - self.x = _x #transverse coordinates of center [m] - self.y = _y + opT = SRWLOptT(nx, ny, rx, ry, None, 1, fx, fy, _xc, _yc, ne, _e_start, _e_fin) -class SRWLOptWG(SRWLOpt): - """Optical Element: Waveguide""" + halfApert = 0.5*_apert_h + halfApertV = 0.5*_apert_v + + if(_foc_plane == 2): #1D lens, vertical is focusing plane + halfApert = halfApertV + elif(_foc_plane == 3): #2D lens + if(halfApert > halfApertV): + halfApert = halfApertV - def __init__(self, _L=1, _Dx=10e-03, _Dy=10e-03, _x=0, _y=0): - """ - :param _L: length [m] - :param _Dx: horizontal transverse dimension [m] - :param _Dy: vertical transverse dimension [m] - :param _x: horizontal transverse coordinate of center [m] - :param _y: vertical transverse coordinate of center [m] - """ - self.L = _L #length [m] - self.Dx = _Dx #transverse dimensions [m] - self.Dy = _Dy - self.x = _x #transverse coordinates of center [m] - self.y = _y + hx = rx/(nx - 1) + hy = ry/(ny - 1) -class SRWLOptG(SRWLOpt): - """Optical Element: Grating (planar)""" + fact_opt_path_n = _n #OC19042018 + complexRotCase = False + if((kxRay != 0) or (kyRay != 0)): + if(((kxRay != 0) and (_foc_plane == 2)) or ((kyRay != 0) and (_foc_plane == 1))): fact_opt_path_n = fact_opt_path*_n + else: complexRotCase = True - def __init__(self, _grDen=100, _disPl='v', _ang=0.7854, _m=1, _refl=1): - """ - :param _grDen: groove density [lines/mm] - :param _disPl: dispersion plane: 'x' ('h') or 'y' ('v') - :param _ang: angle between optical axis and grating plane [rad] - :param _m: output order - :param _refl: average reflectivity (with respect to intensity) - """ - self.grDen = _grDen #groove density [lines/mm] - self.disPl = _disPl #dispersion plane: 'x' ('h') or 'y' ('v') - self.ang = _ang #angle between optical axis and grating plane [rad] - self.m = _m #output order - self.refl = _refl #average reflectivity (with resp. to intensity) + #Same data alignment as for wavefront: outmost loop vs y, inmost loop vs e + ofst = 0 + y = -0.5*ry #CRL is always centered on the grid, however grid can be shifted + for iy in range(ny): + x = -0.5*rx + for ix in range(nx): + #pathInBody = _n*ray_path_in_one_CRL(x, y, _foc_plane, _shape, halfApert, _r_min, _wall_thick) + #OC20042018 + if complexRotCase: + pathInBody = fact_opt_path_n*ray_path_in_one_CRL_rot(x, y, _foc_plane, _shape, halfApert, _r_min, _wall_thick, kxRay, kyRay) + else: + pathInBody = fact_opt_path_n*ray_path_in_one_CRL(x, y, _foc_plane, _shape, halfApert, _r_min, _wall_thick) + + if(_void_cen_rad is not None): #eventually subtract path in voids + pathInBody -= ray_path_in_spheres(x, y, _void_cen_rad) -class SRWLOptT(SRWLOpt): - """Optical Element: Transmission (generic)""" + for ie in range(ne): + opT.arTr[ofst] = exp(-0.5*pathInBody/arAttenLen[ie]) #amplitude transmission + opT.arTr[ofst + 1] = -arDelta[ie]*pathInBody #optical path difference + ofst += 2 + x += hx + y += hy + + opT.input_parms = input_parms #MR16022016 + return opT + +#**************************************************************************** +def srwl_opt_setup_cyl_fiber(_foc_plane, _delta_ext, _delta_core, _atten_len_ext, _atten_len_core, _diam_ext, _diam_core, _xc, _yc): + """ + Setup Transmission type Optical Element which simulates Cylindrical Fiber + :param _foc_plane: plane of focusing: 1- horizontal (i.e. fiber is parallel to vertical axis), 2- vertical (i.e. fiber is parallel to horizontal axis) + :param _delta_ext: refractive index decrement of external layer + :param _delta_core: refractive index decrement of core + :param _atten_len_ext: attenuation length [m] of external layer + :param _atten_len_core: attenuation length [m] of core + :param _diam_ext: diameter [m] of external layer + :param _diam_core: diameter [m] of core + :param _xc: horizontal coordinate of center [m] + :param _yc: vertical coordinate of center [m] + :return: transmission (SRWLOptT) type optical element which simulates Cylindrical Fiber + """ + + input_parms = { #MR26022016: Added all input parameters to include in return object: + "type": "cyl_fiber", + "focalPlane": _foc_plane, + "externalRefractiveIndex": _delta_ext, + "coreRefractiveIndex": _delta_core, + "externalAttenuationLength": _atten_len_ext, + "coreAttenuationLength": _atten_len_core, + "externalDiameter": _diam_ext, + "coreDiameter": _diam_core, + "horizontalCenterPosition": _xc, + "verticalCenterPosition": _yc, + } + + def ray_path_in_cyl(_dx, _diam): + r = 0.5*_diam + pathInCyl = 0 + if((_dx > -r) and (_dx < r)): + pathInCyl = 2*sqrt(r*r - _dx*_dx) + return pathInCyl + + ne = 1 + nx = 101 + ny = 1001 + rx = 10e-03 + ry = _diam_ext*1.2 + if(_foc_plane == 1): #focusing plane is horizontal + nx = 1001 + ny = 101 + rx = _diam_ext*1.2 + ry = 10e-03 + + opT = SRWLOptT(nx, ny, rx, ry, None, 1, 1e+23, 1e+23, _xc, _yc) + + hx = rx/(nx - 1) + hy = ry/(ny - 1) + ofst = 0 + pathInExt = 0 + pathInCore = 0 + + if(_foc_plane == 2): #focusing plane is vertical + y = -0.5*ry #cylinder is always centered on the grid, however grid can be shifted + for iy in range(ny): + pathInExt = 0; pathInCore = 0 + if(_diam_core > 0): + pathInCore = ray_path_in_cyl(y, _diam_core) + pathInExt = ray_path_in_cyl(y, _diam_ext) - pathInCore + argAtten = -0.5*pathInExt/_atten_len_ext + if(_atten_len_core > 0): + argAtten -= 0.5*pathInCore/_atten_len_core + ampTr = exp(argAtten) #amplitude transmission + optPathDif = -_delta_ext*pathInExt - _delta_core*pathInCore #optical path difference + for ix in range(nx): + opT.arTr[ofst] = ampTr #amplitude transmission + opT.arTr[ofst + 1] = optPathDif #optical path difference + ofst += 2 + y += hy + else: #focusing plane is horizontal + perY = 2*nx + x = -0.5*rx #cylinder is always centered on the grid, however grid can be shifted + for ix in range(nx): + pathInExt = 0; pathInCore = 0 + if(_diam_core > 0): + pathInCore = ray_path_in_cyl(x, _diam_core) + pathInExt = ray_path_in_cyl(x, _diam_ext) - pathInCore + argAtten = -0.5*pathInExt/_atten_len_ext + if(_atten_len_core > 0): + argAtten -= 0.5*pathInCore/_atten_len_core + ampTr = exp(argAtten) #amplitude transmission + optPathDif = -_delta_ext*pathInExt - _delta_core*pathInCore #optical path difference + ix2 = ix*2 + for iy in range(ny): + ofst = iy*perY + ix2 + opT.arTr[ofst] = ampTr #amplitude transmission + opT.arTr[ofst + 1] = optPathDif #optical path difference + x += hx + + opT.input_parms = input_parms #MR26022016 + return opT + +#**************************************************************************** +#OC: To rename "mask" to something more meaningful, using general physical/technical terms +def srwl_opt_setup_mask(_delta, _atten_len, _thick, + _hx, _hy, _pitch_x, _pitch_y, _mask_Nx, _mask_Ny, + _grid_nx, _grid_ny, _grid_sh, _grid_dx, _grid_dy=0, _grid_angle=0, _mask_x0=0, _mask_y0=0): + """Setup Transmission type Optical Element which simulates a mask array for at-wavelength metrology. + + :param _delta: refractive index decrement (can be one number of array vs photon energy) + :param _atten_len: attenuation length [m] (can be one number of array vs photon energy) + :param _thick: thickness of mask [m] + :param _hx: sampling interval in x-direction [m] + :param _hy: sampling interval in y-direction [m] + :param _pitch_x: grid pitch in x-direction [m] + :param _pitch_y: grid pitch in y-direction [m] + :param _mask_Nx: number of pixels in x-direction [1] + :param _mask_Ny: number of pixels in y-direction [1] + :param _grid_nx: number of grids in x-direction + :param _grid_ny: number of grids in y-direction + :param _grid_sh: grid shape (0: Circular grids case. 1: Rectangular grids case. 2: 2-D phase grating) + :param _grid_dx: grid dimension in x-direction, width for rectangular or elliptical grids [m] + :param _grid_dy: grid dimension in y-direction, height for rectangular or elliptical grids [m] + :param _grid_angle: tilt angle of the grid [rad] + :param _mask_x0: horizontal coordinate of the mask [m] + :param _mask_y0: vertical coordinate of the mask [m] + :return: transmission (SRWLOptT) type optical element which simulates the PMA + """ + + input_parms = { #MR29092016: Added all input parameters to include in return object: + "type": "mask", + "refractiveIndex": _delta, + "attenuationLength": _atten_len, + "maskThickness": _thick, + "gridShape": _grid_sh, + "horizontalGridDimension": _grid_dx, + "verticalGridDimension": _grid_dy, + "horizontalGridPitch": _pitch_x, + "verticalGridPitch": _pitch_y, + "horizontalGridsNumber": _grid_nx, + "verticalGridsNumber": _grid_ny, + "horizontalPixelsNumber": _mask_Nx, + "verticalPixelsNumber": _mask_Ny, + "gridTiltAngle": _grid_angle, + "horizontalSamplingInterval": _hx, + "verticalSamplingInterval": _mask_Ny, + "horizontalMaskCoordinate": _mask_x0, + "verticalMaskCoordinate": _mask_y0, + } - def __init__(self, _nx=1, _ny=1, _rx=1e-03, _ry=1e-03, _arTr=None, _extTr=0, _Fx=1e+23, _Fy=1e+23, _x=0, _y=0, _ne=1, _eStart=0, _eFin=0): - """ - :param _nx: number of transmission data points in the horizontaldirection - :param _ny: number of transmission data points in the vertical direction - :param _rx: range of the horizontal coordinate [m] for which the transmission is defined - :param _ry: range of the vertical coordinate [m] for which the transmission is defined - :param _arTr: complex C-aligned data array (of 2*ne*nx*ny length) storing amplitude transmission and optical path difference as function of transverse coordinates - :param _extTr: transmission outside the grid/mesh is zero (0), or it is same as on boundary (1) - :param _Fx: estimated focal length in the horizontal plane [m] - :param _Fy: estimated focal length in the vertical plane [m] - :param _x: horizontal transverse coordinate of center [m] - :param _y: vertical transverse coordinate of center [m] - :param _ne: number of transmission data points vs photon energy - :param _eStart: initial value of photon energy - :param _eFin: final value of photon energy - """ - self.arTr = _arTr #complex C-aligned data array (of 2*ne*nx*ny length) storing amplitude transmission and optical path difference as function of transverse position - if((_arTr == None) or ((len(_arTr) != _ne*_nx*_ny*2) and (_ne*_nx*_ny > 0))): - self.allocate(_ne, _nx, _ny) - self.ne = _ne #number of transmission data points vs photon energy - self.nx = _nx #numbers of transmission data points in the horizontal and vertical directions - self.ny = _ny - self.eStart = _eStart #initial and final values of photon energy - self.eFin = _eFin - self.rx = _rx #ranges of horizontal and vertical coordinates [m] for which the transmission is defined - self.ry = _ry - self.extTr = _extTr #0- transmission outside the grid/mesh is zero; 1- it is same as on boundary - self.Fx = _Fx #estimated focal lengths [m] - self.Fy = _Fy - self.x = _x #transverse coordinates of center [m] - self.y = _y - #if _ne > 1: _Fx, _Fy should be arrays vs photon energy? + # Check if _grid_dy is set by user. + if _grid_dy == 0: + _grid_dy = _grid_dx # An ellipse becomes a circle and a rectangle becomes a square. + if _grid_sh == 2: + _grid_dx = _pitch_x # Change grid_size for 2D grating, grid_size equal to pitch + _grid_dy = _pitch_y + # Calculate the range of mask. + mask_Rx = _hx * _mask_Nx # mask range in x-direction [m]. + mask_Ry = _hy * _mask_Nx # mask range in y-direction [m]. + + # Calculate the range of grid. + grid_Rx = _pitch_x * _grid_nx # grid range in x-direction [m]. + grid_Ry = _pitch_y * _grid_ny # grid range in y-direction [m]. + + # Generate Transmission Optical Element. + trans_opt = SRWLOptT(_nx=_mask_Nx, _ny=_mask_Ny, _rx=mask_Rx, _ry=mask_Ry, _arTr=None, _extTr=0, _x=0, _y=0) + + # Same data alignment as for wavefront: outer loop vs y, inner loop vs x. + pointer = 0 # pointer for array trans_opt.arTr + y = - mask_Ry / 2 # Mask is always centered on the grid, however grid can be shifted. + + #Calculate aux. constants for equations for edges of rectangle. + xCross1 = None; yCross1 = None #OC27012017 + xCross2 = None; yCross2 = None + k1 = None; k2 = None; k3 = None; k4 = None + if(_grid_sh == 1): + grid_dx_d_sqrt2 = _grid_dx / sqrt(2) + cosGridAng = cos(_grid_angle) + sinGridAng = sin(_grid_angle) + xCross2 = grid_dx_d_sqrt2 * cosGridAng + #xCross1 = - grid_dx_d_sqrt2 * cosGridAng + xCross1 = -xCross2 + yCross2 = grid_dx_d_sqrt2 * sinGridAng + #yCross1 = - grid_dx_d_sqrt2 * sinGridAng + yCross1 = -yCross2 + k1 = tan(pi / 4 + _grid_angle) + k2 = -tan(pi / 4 - _grid_angle) + k4 = tan(pi / 4 + _grid_angle) + k3 = -tan(pi / 4 - _grid_angle) + + for iy in range(_mask_Ny): + # Calculate the relative position in y. + # NOTE: Use round to solve the precision issue! + pitch_num_y = floor(round(y / _pitch_y, 9)) + y_rel = y - (pitch_num_y * _pitch_y) - _mask_y0 + if y_rel >= _pitch_y / 2: + y_rel -= _pitch_y + + x = - mask_Rx / 2 # Mask is always centered on the grid, however grid can be shifted. + for ix in range(_mask_Nx): + # Calculate the relative position in x. + # NOTE: Use round to solve the precision issue! + pitch_num_x = floor(round(x / _pitch_x, 9)) + x_rel = x - (pitch_num_x * _pitch_x) - _mask_x0 + + if x_rel >= _pitch_x / 2: + x_rel -= _pitch_x + + # Initialize the bool parameter. + inside_hole = False + phase_shift = False + + # Hartmann hole in an elliptical shape. + if _grid_sh == 0: + if (x_rel / _grid_dx) ** 2 + (y_rel / _grid_dy) ** 2 < 1 \ + and not (round(x_rel - (x - _mask_x0), 9) == 0 and round(y_rel - (y - _mask_y0), 9) == 0) \ + and abs(x) < grid_Rx / 2 and abs(y) < grid_Ry / 2: + inside_hole = True + + # Hartmann hole in a rectangular shape. + elif _grid_sh == 1: + # Calculate the equations for edges of rectangle. + #OC27012017 (commented-out, calculation of these constants was moved outside of the loop) + #xCross1 = - _grid_dx / (2 ** 0.5) * math.cos(_grid_angle) + #yCross1 = - _grid_dx / (2 ** 0.5) * math.sin(_grid_angle) + #xCross2 = + _grid_dx / (2 ** 0.5) * math.cos(_grid_angle) + #yCross2 = + _grid_dx / (2 ** 0.5) * math.sin(_grid_angle) + #k1 = math.tan(math.pi / 4 + _grid_angle) + #k2 = -math.tan(math.pi / 4 - _grid_angle) + #k4 = math.tan(math.pi / 4 + _grid_angle) + #k3 = -math.tan(math.pi / 4 - _grid_angle) + + if (k2 * x_rel + (yCross2 - k2 * xCross2)) > y_rel > (k3 * x_rel + (yCross1 - k3 * xCross1)) \ + and (k1 * x_rel + (yCross1 - k1 * xCross1)) > y_rel > (k4 * x_rel + (yCross2 - k4 * xCross2)) \ + and not (abs(x - _mask_x0) < _pitch_x / 2 and abs(y - _mask_y0) < _pitch_y / 2) \ + and abs(x) < grid_Rx / 2 and abs(y) < grid_Ry / 2: + inside_hole = True + + # Grating shearing interferometry in a 2D phase grating. + elif _grid_sh == 2: + phase_shift = False + if (x_rel >= 0 and y_rel < 0) or (x_rel < 0 and y_rel >= 0): + phase_shift = True + + else: + raise ValueError('Unknown shape code.') + + # Give values to trans_opt.arTr. + if inside_hole and not (_grid_sh == 2): + trans_opt.arTr[pointer] = 1 # amplitude transmission. (!) not in physics yet + trans_opt.arTr[pointer + 1] = 0 # optical path difference. (!) not in physics yet + else: + trans_opt.arTr[pointer] = 0 # amplitude transmission. (!) not in physics yet + trans_opt.arTr[pointer + 1] = 0 # optical path difference. (!) not in physics yet + + if _grid_sh == 2: + # Give values to OpT.arTr + # Make final judgement. + if phase_shift: + trans_opt.arTr[pointer] = exp(-0.5 * _thick / _atten_len) # amplitude transmission. + trans_opt.arTr[pointer + 1] = -_delta * _thick # optical path difference. + else: + trans_opt.arTr[pointer] = 1 # amplitude transmission. + trans_opt.arTr[pointer + 1] = 0 # optical path difference. + if not (abs(x) < grid_Rx / 2 and abs(y) < grid_Ry / 2): # check if it is in grid area + trans_opt.arTr[pointer] = 0 + trans_opt.arTr[pointer + 1] = 0 + + # Shift the pointer by 2. + pointer += 2 + + # Step x by _hx. + x += _hx + + # Step y by _hy. + y += _hy + + trans_opt.input_parms = input_parms #MR29092016 + return trans_opt + +#**************************************************************************** +def srwl_opt_setup_surf_height_1d(_height_prof_data, _dim, _ang, _ang_r=0, _amp_coef=1, _ar_arg_long=None, _nx=0, _ny=0, _size_x=0, _size_y=0, _xc=0, _yc=0): #OC19072018 + """ + Setup Transmission type optical element with 1D (mirror or grating) surface Heght Profile data + :param _height_prof_data: two- or one-column table containing, in case of two columns: longitudinal position in [m] (1st column) and the Height Profile in [m] (2nd column) data; in case of one column, it contains the Height Profile data + :param _dim: orientation of the reflection (deflection) plane; can be 'x' or 'y' + :param _ang: grazing angle (between input optical axis and mirror/grating plane) + :param _ang_r: reflection angle (between output optical axis and mirror/grating plane) + :param _amp_coef: height profile "amplification coefficient" + :param _ar_arg_long: optional array of longitudinal position (along mirror/grating) in [m]; if _ar_arg_long is not None, any longitudinal position contained in _height_prof_data is ignored + :param _nx: optional number of points in horizontal dimension of the output transmission optical element + :param _ny: optional number of points in vertical dimension of the output transmission optical element + :param _size_x: optional horizontal transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :param _size_y: optional vertical transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :param _xc: optional horizontal center position of the output transmission optical element + :param _yc: optional vertical center position of the output transmission optical element + :return: transmission (SRWLOptT) type optical element which simulates the effect of surface height error + """ + #To test all options! + + input_parms = { #MR26022016: Added all input parameters to include in return object: + "type": "mirror", + "heightProfileFile": "", + "orientation": _dim, + "grazingAngle": _ang, + "reflectionAngle": _ang_r, + "heightAmplification": _amp_coef, + "longitudinalPosition": _ar_arg_long, + "horizontalPoints": _nx, + "verticalPoints": _ny, + "horizontalTransverseSize": _size_x, + "verticalTransverseSize": _size_y, + "horizontalCenterPosition": _xc, + "verticalCenterPosition": _yc, + } + + if((_dim != 'x') and (_dim != 'y')): raise Exception('The orientation of the deflection plane can be either horizontal (\'x\') or vertical (\'y\')') + + if(_ang_r == 0): _ang_r = _ang + sinAng = sin(_ang) + sinAngR = sin(_ang_r) + + if _ar_arg_long is None: + argHeightProfData = _height_prof_data[0] + valHeightProfData = _height_prof_data[1] + else: + argHeightProfData = _ar_arg_long + if len(_height_prof_data) >= 2: + valHeightProfData = _height_prof_data[1] + else: valHeightProfData = _height_prof_data[0] + + npData = len(valHeightProfData) + npDataTr = 100 #default value + sizeLongProj = (argHeightProfData[npData - 1] - argHeightProfData[0])*sinAngR + sizeTr = 1 #default value + + nx = _nx + if nx <= 0: + if('x' in _dim): nx = npData + else: nx = npDataTr + ny = _ny + if ny <= 0: + if('y' in _dim): ny = npData + else: ny = npDataTr + + if _size_x > 0: sizeX = _size_x + else: + sizeX = sizeLongProj + if('y' in _dim): sizeX = sizeTr + + if _size_y > 0: sizeY = _size_y + else: + sizeY = sizeTr + if('y' in _dim): sizeY = sizeLongProj + + optSlopeErr = SRWLOptT(nx, ny, sizeX, sizeY, _x=_xc, _y=_yc) + + auxMesh = optSlopeErr.mesh + xStep = (auxMesh.xFin - auxMesh.xStart)/(auxMesh.nx - 1) + yStep = (auxMesh.yFin - auxMesh.yStart)/(auxMesh.ny - 1) + + perX = 2 + perY = 2*auxMesh.nx - def allocate(self, _ne, _nx, _ny): - self.ne = _ne - self.nx = _nx - self.ny = _ny - nTot = 2*_ne*_nx*_ny #total array length to store amplitude transmission and optical path difference - self.arTr = array('d', [0]*nTot) + hApprox = 0 + ipStart = 0 -class SRWLOptMir(SRWLOpt): - """Optical Element: Mirror (focusing)""" + #OCTEST + #print('Heigh profile: nx=', auxMesh.nx, ' ny=', auxMesh.ny) - def set_dim_sim_meth(self, _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0): - """Sets Mirror Dimensions, Aperture Shape and its simulation method - :param _size_tang: size in tangential direction [m] - :param _size_sag: size in sagital direction [m] - :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) - :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) - :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) - :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) - :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: - 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; - 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; - 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; - :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters - :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters - """ - if((_sim_meth < 1) or (_sim_meth > 2)): - raise Exception("Simulation method is not specified correctly (should be 1 for \"thin\", 2 for \"thick\" element approximation)") - self.dt = _size_tang - self.ds = _size_sag - self.apShape = _ap_shape - self.meth = _sim_meth - self.npt = _npt - self.nps = _nps - self.treatInOut = _treat_in_out - self.extIn = _ext_in - self.extOut = _ext_out - self.Fx = 0 #i.e. focal lengthes are not set - self.Fy = 0 + #if('y' in _dim): + arg1Start = auxMesh.yStart - _yc + arg2Start = auxMesh.xStart - _xc + n1 = auxMesh.ny; n2 = auxMesh.nx + per1 = perY; per2 = perX + arg1Step = yStep; arg2Step = xStep + + if('x' in _dim): + arg1Start = auxMesh.xStart - _xc + arg2Start = auxMesh.yStart - _yc + n1 = auxMesh.nx; n2 = auxMesh.ny + per1 = perX; per2 = perY + arg1Step = xStep; arg2Step = yStep - def set_reflect(self, _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=0, _ph_en_fin=0, _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): - """Sets Mirror Reflectivity - :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat array complex array vs photon energy vs grazing angle vs component (sigma, pi)) - :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified - :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified - :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) - :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified - :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified - :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) - :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified - :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified - :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) - """ - nTot = int(_n_ph_en*_n_ang*_n_comp*2) - if(nTot < 2): - raise Exception("Incorrect Reflectivity array parameters") - _n_comp = int(_n_comp) - if((_n_comp < 1) or (_n_comp > 2)): - raise Exception("Number of reflectivity coefficient components can be 1 or 2") + arg1 = arg1Start #to make sure that only the mesh moves + for i1 in range(n1): + hApprox = 0 + arg1_1 = argHeightProfData[ipStart]*sinAngR + for i in range(ipStart + 1, npData): + arg1_2 = argHeightProfData[i]*sinAngR + if((arg1_1 <= arg1) and (arg1 < arg1_2)): + hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAngR))*(arg1 - arg1_1) + valHeightProfData[i-1] + ipStart = i - 1 + break + arg1_1 = arg1_2 + + per1_i1 = per1*i1 + arg2 = arg2Start #to make sure that only the mesh moves + for i2 in range(n2): + ofst = per2*i2 + per1_i1 + optSlopeErr.arTr[ofst] = 1. #Amplitude Transmission #consider taking into account reflectivity + optSlopeErr.arTr[ofst + 1] = 0. #Optical Path Difference + if(hApprox != 0): + optSlopeErr.arTr[ofst + 1] = -(sinAng + sinAngR)*hApprox*_amp_coef #Optical Path Difference (to check sign!) + + arg2 += arg2Step + arg1 += arg1Step + + optSlopeErr.input_parms = input_parms #MR16022016 + return optSlopeErr + +#**************************************************************************** +def srwl_opt_setup_surf_height_1d_old(_height_prof_data, _dim, _ang, _ang_r=0, _amp_coef=1, _ar_arg_long=None, _nx=0, _ny=0, _size_x=0, _size_y=0, _xc=0, _yc=0): + #OC19072018: This version is very slow for _dim = 'x' with Py 2.7 + """ + Setup Transmission type optical element with 1D (mirror or grating) surface Heght Profile data + :param _height_prof_data: two- or one-column table containing, in case of two columns: longitudinal position in [m] (1st column) and the Height Profile in [m] (2nd column) data; in case of one column, it contains the Height Profile data + :param _dim: orientation of the reflection (deflection) plane; can be 'x' or 'y' + :param _ang: grazing angle (between input optical axis and mirror/grating plane) + :param _ang_r: reflection angle (between output optical axis and mirror/grating plane) + :param _amp_coef: height profile "amplification coefficient" + :param _ar_arg_long: optional array of longitudinal position (along mirror/grating) in [m]; if _ar_arg_long is not None, any longitudinal position contained in _height_prof_data is ignored + :param _nx: optional number of points in horizontal dimension of the output transmission optical element + :param _ny: optional number of points in vertical dimension of the output transmission optical element + :param _size_x: optional horizontal transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :param _size_y: optional vertical transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :param _xc: optional horizontal center position of the output transmission optical element + :param _yc: optional vertical center position of the output transmission optical element + :return: transmission (SRWLOptT) type optical element which simulates the effect of surface height error + """ + #To test all options! + + input_parms = { #MR26022016: Added all input parameters to include in return object: + "type": "mirror", + "heightProfileFile": "", + "orientation": _dim, + "grazingAngle": _ang, + "reflectionAngle": _ang_r, + "heightAmplification": _amp_coef, + "longitudinalPosition": _ar_arg_long, + "horizontalPoints": _nx, + "verticalPoints": _ny, + "horizontalTransverseSize": _size_x, + "verticalTransverseSize": _size_y, + "horizontalCenterPosition": _xc, + "verticalCenterPosition": _yc, + } + + if(_ang_r == 0): _ang_r = _ang + sinAng = sin(_ang) + sinAngR = sin(_ang_r) + + if _ar_arg_long is None: + argHeightProfData = _height_prof_data[0] + valHeightProfData = _height_prof_data[1] + else: + argHeightProfData = _ar_arg_long + if len(_height_prof_data) >= 2: + valHeightProfData = _height_prof_data[1] + else: valHeightProfData = _height_prof_data[0] + + npData = len(valHeightProfData) + npDataTr = 100 #default value + sizeLongProj = (argHeightProfData[npData - 1] - argHeightProfData[0])*sinAngR + sizeTr = 1 #default value + + nx = _nx + if nx <= 0: + if('x' in _dim): nx = npData + else: nx = npDataTr + ny = _ny + if ny <= 0: + if('y' in _dim): ny = npData + else: ny = npDataTr + + if _size_x > 0: sizeX = _size_x + else: + sizeX = sizeLongProj + if('y' in _dim): sizeX = sizeTr + + if _size_y > 0: sizeY = _size_y + else: + sizeY = sizeTr + if('y' in _dim): sizeY = sizeLongProj + + #optSlopeErr = SRWLOptT(nx, ny, sizeX, sizeY) + optSlopeErr = SRWLOptT(nx, ny, sizeX, sizeY, _x=_xc, _y=_yc) + + auxMesh = optSlopeErr.mesh + xStep = (auxMesh.xFin - auxMesh.xStart)/(auxMesh.nx - 1) + yStep = (auxMesh.yFin - auxMesh.yStart)/(auxMesh.ny - 1) + + #y = auxMesh.yStart + y = auxMesh.yStart - _yc #to make sure that only the mesh moves + hApprox = 0 + ipStart = 0 + + #OCTEST + #print('Heigh profile: nx=', auxMesh.nx, ' ny=', auxMesh.ny) - if(not(isinstance(_refl, list) or isinstance(_refl, array))): - self.arRefl = array('d', [_refl]*nTot) - for i in range(int(round(nTot/2))): - i2 = i*2 - self.arRefl[i2] = _refl - self.arRefl[i2 + 1] = 0 - else: - self.arRefl = _refl + #for iy in range(optSlopeErr.ny): + for iy in range(auxMesh.ny): + if('y' in _dim): + hApprox = 0 + y1 = argHeightProfData[ipStart]*sinAngR + for i in range(ipStart + 1, npData): + y2 = argHeightProfData[i]*sinAngR + if((y1 <= y) and (y < y2)): + hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAngR))*(y - y1) + valHeightProfData[i-1] + #hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAng))*(y - y1) + valHeightProfData[i-1] + #print(ipStart, i, iy, y1, y, y2, argHeightProfData[i-1], argHeightProfData[i], valHeightProfData[i-1], valHeightProfData[i], hApprox) + ipStart = i - 1 + break + y1 = y2 + + #x = auxMesh.xStart + x = auxMesh.xStart - _xc #to make sure that only the mesh moves - self.reflNumPhEn = int(_n_ph_en) - self.reflNumAng = int(_n_ang) - self.reflNumComp = _n_comp - self.reflPhEnStart = _ph_en_start - self.reflPhEnFin = _ph_en_fin - self.reflPhEnScaleType = _ph_en_scale_type - self.reflAngStart = _ang_start - self.reflAngFin = _ang_fin - self.reflAngScaleType = _ang_scale_type + #for ix in range(optSlopeErr.nx): + for ix in range(auxMesh.nx): + if('x' in _dim): + if(ix == 0): ipStart = 0 + hApprox = 0 + x1 = argHeightProfData[ipStart]*sinAngR + for i in range(ipStart + 1, npData): + x2 = argHeightProfData[i]*sinAngR + if((x1 <= x) and (x < x2)): + hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAngR))*(x - x1) + valHeightProfData[i-1] + #hApprox = ((valHeightProfData[i] - valHeightProfData[i-1])/((argHeightProfData[i] - argHeightProfData[i-1])*sinAng))*(x - x1) + valHeightProfData[i-1] + ipStart = i - 1 + break + x1 = x2 + #ofst = 2*ix + (2*optSlopeErr.nx)*iy + ofst = 2*ix + (2*auxMesh.nx)*iy - def set_orient(self, _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0): - """Defines Mirror Orientation in the frame of the incident photon beam - :param _nvx: horizontal coordinate of central normal vector [m] - :param _nvy: vertical coordinate of central normal vector [m] - :param _nvz: longitudinal coordinate of central normal vector [m] - :param _tvx: horizontal coordinate of central tangential vector [m] - :param _tvy: vertical coordinate of central tangential vector [m] - :param _x: horizontal position of mirror center - :param _y: vertical position of mirror center - """ - self.nvx = _nvx - self.nvy = _nvy - self.nvz = _nvz - self.tvx = _tvx - self.tvy = _tvy - self.x = _x - self.y = _y - self.Fx = 0 #i.e. focal lengthes are not set - self.Fy = 0 + optSlopeErr.arTr[ofst] = 1. #Amplitude Transmission #consider taking into account reflectivity + optSlopeErr.arTr[ofst + 1] = 0. #Optical Path Difference + if(hApprox != 0): + #optSlopeErr.arTr[ofst + 1] = -2*sinAng*hApprox #Optical Path Difference (to check sign!) + optSlopeErr.arTr[ofst + 1] = -(sinAng + sinAngR)*hApprox*_amp_coef #Optical Path Difference (to check sign!) + #print(ix, iy, optSlopeErr.arTr[ofst + 1]) + x += xStep + y += yStep -class SRWLOptMirEl(SRWLOptMir): - """Optical Element: Mirror: Ellipsoid""" + optSlopeErr.input_parms = input_parms #MR16022016 + return optSlopeErr + +#**************************************************************************** +def srwl_opt_setup_surf_height_2d(_height_prof_data, _dim, _ang, _ang_r=0, _amp_coef=1, _ar_arg_long=None, _ar_arg_tr=None, _nx=0, _ny=0, _size_x=0, _size_y=0): + """ + Setup Transmission type optical element with 2D (mirror or grating) surface Heght Profile data + :param _height_prof_data: a matrix (2D array) containing the Height Profile data in [m]; if _ar_height_prof_x is None and _ar_height_prof_y is None: the first column in _height_prof_data is assumed to be the "longitudinal" position [m] and first row the "transverse" position [m], and _height_prof_data[0][0] is not used; otherwise the "longitudinal" and "transverse" positions on the surface are assumed to be given by _ar_height_prof_x, _ar_height_prof_y + :param _dim: orientation of the reflection (deflection) plane; can be 'x' or 'y' + :param _ang: grazing angle (between input optical axis and mirror/grating plane) + :param _ang_r: reflection angle (between output optical axis and mirror/grating plane) + :param _amp_coef: height profile "amplification coefficient" + :param _ar_arg_long: optional array of longitudinal position (along mirror/grating) in [m] + :param _ar_arg_tr: optional array of transverse position on mirror/grating surface in [m] + :param _nx: optional number of points in horizontal dimension of the output transmission optical element + :param _ny: optional number of points in vertical dimension of the output transmission optical element + :param _size_x: optional horizontal transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :param _size_y: optional vertical transverse size of the output transmission optical element (if <=0: _height_prof_data, _dim, _ar_arg_long, _ar_arg_tr data is used) + :return: transmission (SRWLOptT) type optical element which simulates the effect of surface height error + """ + #To test all options! + + input_parms = { #MR26022016: Options will be used for 2D mirror profiles in Sirepo in the future: + #"type": "mirror", + "type": "mirror2d", + "heightProfileFile": "", + "orientation": _dim, + "grazingAngle": _ang, + "reflectionAngle": _ang_r, + "heightAmplification": _amp_coef, + "longitudinalPosition": _ar_arg_long, + "transversePosition": _ar_arg_tr, + "horizontalPoints": _nx, + "verticalPoints": _ny, + "horizontalTransverseSize": _size_x, + "verticalTransverseSize": _size_y, + } + + if(_ang_r == 0): _ang_r = _ang + sinAng = sin(_ang) + sinAngR = sin(_ang_r) - def __init__(self, _p=1, _q=1, _ang_graz=1e-03, _r_sag=1.e+23, - _size_tang=1, _size_sag=1, _ap_shape='r', _sim_meth=2, _npt=500, _nps=500, _treat_in_out=1, _ext_in=0, _ext_out=0, - _nvx=0, _nvy=0, _nvz=-1, _tvx=1, _tvy=0, _x=0, _y=0, - _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=1000., _ph_en_fin=1000., _ph_en_scale_type='lin', _ang_start=0, _ang_fin=0, _ang_scale_type='lin'): - """ - :param _p: distance from first focus (\"source\") to mirror center [m] - :param _q: distance from mirror center to second focus (\"image\") [m] - :param _ang_graz: grazing angle at mirror center at perfect orientation [rad] - :param _r_sag: sagital radius of curvature at mirror center [m] - :param _size_tang: size in tangential direction [m] - :param _size_sag: size in sagital direction [m] - :param _ap_shape: shape of aperture in local frame ('r' for rectangular, 'e' for elliptical) - :param _sim_meth: simulation method (1 for "thin" approximation, 2 for "thick" approximation) - :param _npt: number of mesh points to represent mirror in tangential direction (used for "thin" approximation) - :param _nps: number of mesh points to represent mirror in sagital direction (used for "thin" approximation) - :param _treat_in_out: switch specifying how to treat input and output wavefront before and after the main propagation through the optical element: - 0- assume that the input wavefront is defined in the plane before the optical element, and the output wavefront is required in a plane just after the element; - 1- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; - 2- assume that the input wavefront is defined in the plane at the optical element center and the output wavefront is also required at the element center; however, before the propagation though the optical element, the wavefront should be propagated through a drift back to a plane just before the optical element, then a special propagator will bring the wavefront to a plane at the optical element exit, and after this the wavefront will be propagated through a drift back to the element center; - :param _ext_in: optical element extent on the input side, i.e. distance between the input plane and the optical center (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters - :param _ext_out: optical element extent on the output side, i.e. distance between the optical center and the output plane (positive, in [m]) to be used at wavefront propagation manipulations; if 0, this extent will be calculated internally from optical element parameters - :param _nvx: horizontal coordinate of central normal vector [m] - :param _nvy: vertical coordinate of central normal vector [m] - :param _nvz: longitudinal coordinate of central normal vector [m] - :param _tvx: horizontal coordinate of central tangential vector [m] - :param _tvy: vertical coordinate of central tangential vector [m] - :param _x: horizontal position of mirror center - :param _y: vertical position of mirror center - :param _refl: reflectivity coefficient to set (can be one number or C-aligned flat complex array vs photon energy vs grazing angle vs component (sigma, pi)) - :param _n_ph_en: number of photon energy values for which the reflectivity coefficient is specified - :param _n_ang: number of grazing angle values for which the reflectivity coefficient is specified - :param _n_comp: number of electric field components for which the reflectivity coefficient is specified (can be 1 or 2) - :param _ph_en_start: initial photon energy value for which the reflectivity coefficient is specified - :param _ph_en_fin: final photon energy value for which the reflectivity coefficient is specified - :param _ph_en_scale_type: photon energy sampling type ('lin' for linear, 'log' for logarithmic) - :param _ang_start: initial grazing angle value for which the reflectivity coefficient is specified - :param _ang_fin: final grazing angle value for which the reflectivity coefficient is specified - :param _ang_scale_type: angle sampling type ('lin' for linear, 'log' for logarithmic) - """ - self.p = _p - self.q = _q - self.angGraz = _ang_graz - self.radSag = _r_sag + #argHeightProfData = _ar_arg_long + if _ar_arg_long is None: + npData = len(_height_prof_data[0]) - 1 + sizeLong = _height_prof_data[0][npData - 1] - _height_prof_data[0][1] + else: + npData = len(_ar_arg_long) + sizeLong = _ar_arg_long[npData - 1] - _ar_arg_long[0] - #finishing of the mirror setup requires calling these 3 functions (with their required arguments): - self.set_dim_sim_meth(_size_tang, _size_sag, _ap_shape, _sim_meth, _npt, _nps, _treat_in_out, _ext_in, _ext_out) - self.set_orient(_nvx, _nvy, _nvz, _tvx, _tvy, _x, _y) - self.set_reflect(_refl, _n_ph_en, _n_ang, _n_comp, _ph_en_start, _ph_en_fin, _ph_en_scale_type, _ang_start, _ang_fin, _ang_scale_type) + sizeLongProj = sizeLong*sinAngR -class SRWLOptMirTor(SRWLOptMir): - """Optical Element: Mirror: Ellipsoid""" + if _ar_arg_tr is None: + npDataTr = len(_height_prof_data) - 1 + sizeTr = _height_prof_data[npDataTr - 1][0] - _height_prof_data[1][0] + else: + npDataTr = len(_ar_arg_tr) + sizeTr = _ar_arg_tr[npDataTr - 1] - _ar_arg_tr[0] + + #npData = len(_height_prof_data[0]) + #npDataTr = len(_height_prof_data) + + nx = _nx + if nx <= 0: + if('x' in _dim): nx = npData + else: nx = npDataTr + ny = _ny + if ny <= 0: + if('y' in _dim): ny = npData + else: ny = npDataTr + + if _size_x > 0: sizeX = _size_x + else: + sizeX = sizeLongProj + if('y' in _dim): sizeX = sizeTr + + if _size_y > 0: sizeY = _size_y + else: + sizeY = sizeTr + if('y' in _dim): sizeY = sizeLongProj + + #sizeX = sizeLongProj; sizeY = sizeTr + #if('y' in _dim): + # sizeX = sizeTr; sizeY = sizeLongProj + + optSlopeErr = SRWLOptT(nx, ny, sizeX, sizeY) - def __init__(self, _rt=1, _rs=1): - """ - :param _rt: tangential (major) radius [m] - :param _rs: sagittal (minor) radius [m] - """ - self.radTan = _rt - self.radSag = _rs - - #finishing of the mirror setup requires calling these 3 functions (with their required arguments): - self.set_reflect() - self.set_dim_sim_meth() - self.set_orient() + auxMesh = optSlopeErr.mesh + xStep = (auxMesh.xFin - auxMesh.xStart)/(auxMesh.nx - 1) + yStep = (auxMesh.yFin - auxMesh.yStart)/(auxMesh.ny - 1) -class SRWLOptC(SRWLOpt): - """Optical Element: Container""" + #print(auxMesh.xStart, auxMesh.xFin, auxMesh.nx, xStep) + #print(xStep, yStep) + + y = auxMesh.yStart + hApprox = 0 - def __init__(self, _arOpt=None, _arProp=None): - """ - :param _arOpt: optical element structures list (or array) - :param _arProp: list of lists of propagation parameters to be used for each individual optical element - Each element _arProp[i] is a list in which elements mean: - [0]: Auto-Resize (1) or not (0) Before propagation - [1]: Auto-Resize (1) or not (0) After propagation - [2]: Relative Precision for propagation with Auto-Resizing (1. is nominal) - [3]: Allow (1) or not (0) for semi-analytical treatment of the quadratic (leading) phase terms at the propagation - [4]: Do any Resizing on Fourier side, using FFT, (1) or not (0) - [5]: Horizontal Range modification factor at Resizing (1. means no modification) - [6]: Horizontal Resolution modification factor at Resizing - [7]: Vertical Range modification factor at Resizing - [8]: Vertical Resolution modification factor at Resizing - [9]: Type of wavefront Shift before Resizing (vs which coordinates; not yet implemented) - [10]: New Horizontal wavefront Center position after Shift (not yet implemented) - [11]: New Vertical wavefront Center position after Shift (not yet implemented) - """ - self.arOpt = _arOpt #optical element structures array - if(_arOpt == None): - self.arOpt = [] - self.arProp = _arProp #list of lists of propagation parameters to be used for individual optical elements - if(_arProp == None): - self.arProp = [] + ipStart = 1 + ipStartTr = 1 + + for iy in range(auxMesh.ny): + y1 = 0; y2 = 0 + + if('y' in _dim): + ipStartTr = 1 + #y1 = argHeightProfData[ipStart]*sinAngR + if _ar_arg_long is None: y1 = _height_prof_data[0][ipStart]*sinAngR + else: y1 = _ar_arg_long[ipStart - 1]*sinAngR - def allocate(self, _nElem): - self.arOpt = [SRWLOpt()]*_nElem - self.arProp = [[0]*12]*_nElem + for i in range(ipStart + 1, npData + 1): + #for i in range(ipStart + 1, npData): + #y2 = argHeightProfData[i]*sinAngR + if _ar_arg_long is None: y2 = _height_prof_data[0][i]*sinAngR + else: y2 = _ar_arg_long[i - 1]*sinAngR + + if((y1 <= y) and (y < y2)): + ipStart = i - 1 + break + y1 = y2 -#**************************************************************************** -#**************************************************************************** -#Setup some transmission-type optical elements -#**************************************************************************** -#**************************************************************************** -def srwl_opt_setup_CRL(_foc_plane, _delta, _atten_len, _shape, _apert_h, _apert_v, _r_min, _n, _wall_thick, _xc, _yc, _void_cen_rad=None, _e_start=0, _e_fin=0): - """ - Setup Transmission type Optical Element which simulates Compound Refractive Lens (CRL) - :param _foc_plane: plane of focusing: 1- horizontal, 2- vertical, 3- both - :param _delta: refractive index decrement (can be one number of array vs photon energy) - :param _atten_len: attenuation length [m] (can be one number of array vs photon energy) - :param _shape: 1- parabolic, 2- circular (spherical) - :param _apert_h: horizontal aperture size [m] - :param _apert_v: vertical aperture size [m] - :param _r_min: radius (on tip of parabola for parabolic shape) [m] - :param _n: number of lenses ("holes") - :param _wall_thick: min. wall thickness between "holes" [m] - :param _xc: horizontal coordinate of center [m] - :param _yc: vertical coordinate of center [m] - :param _void_cen_rad: flat array/list of void center coordinates and radii: [x1, y1, r1, x2, y2, r2,...] - :param _e_start: initial photon energy - :param _e_fin: final photon energy - :return: transmission (SRWLOptT) type optical element which simulates CRL - """ - def ray_path_in_one_CRL(_x, _y, _foc_plane, _shape, _half_apert, _r_min, _wall_thick): #CRL is always centered - rE2 = 0 - if((_foc_plane == 1) or (_foc_plane == 3)): #focusing in horizontal plane - rE2 += _x*_x - if((_foc_plane == 2) or (_foc_plane == 3)): #focusing in vertical or in both planes - rE2 += _y*_y + elif('x' in _dim): + ipStart = 1 + if _ar_arg_tr is None: y1 = _height_prof_data[ipStartTr][0] + else: y1 = _ar_arg_tr[ipStartTr - 1] - halfApE2 = _half_apert*_half_apert - - sectLen = 0 - if(_shape == 1): #parabolic - a = 1./_r_min - sectLen = _wall_thick + a*halfApE2 - if(rE2 < halfApE2): - return _wall_thick + a*rE2 - elif(_shape == 2): #circular (or spherical) - radE2 = _r_min*_r_min - sectLen = _wall_thick + 2*_r_min - if(_half_apert < _r_min): - sectLen = _wall_thick + 2*(_r_min - sqrt(radE2 - halfApE2)) - if(rE2 < halfApE2): - return sectLen - 2*sqrt(radE2 - rE2) - elif(rE2 < radE2): - return sectLen - 2*sqrt(radE2 - rE2) - return sectLen + for i in range(ipStartTr + 1, npDataTr + 1): + #for i in range(ipStartTr + 1, npDataTr): + if _ar_arg_tr is None: y2 = _height_prof_data[i][0] + else: y2 = _ar_arg_tr[i - 1] + + if((y1 <= y) and (y < y2)): + ipStartTr = i - 1 + break + y1 = y2 - def ray_path_in_spheres(_x, _y, _void_cen_rad): - n = int(round(len(_void_cen_rad)/3)) - sumPath = 0. - for i in range(n): - i3 = i*3 - dx = _x - _void_cen_rad[i3] - dy = _y - _void_cen_rad[i3 + 1] - rVoid = _void_cen_rad[i3 + 2] - uE2 = dx*dx + dy*dy - rVoidE2 = rVoid*rVoid - if(uE2 < rVoidE2): - sumPath += 2*sqrt(rVoidE2 - uE2) - #print('Void crossed:', dx, dy, rVoid, sumPath) - return sumPath + x = auxMesh.xStart + for ix in range(auxMesh.nx): + x1 = 0; x2 = 0 + + if('y' in _dim): + if(ix == 0): ipStartTr = 1 + + if _ar_arg_tr is None: x1 = _height_prof_data[ipStartTr][0] + else: x1 = _ar_arg_tr[ipStartTr - 1] - foc_len = (0.5*_r_min/(_n*_delta)) - print('Optical Element Setup: CRL Focal Length:', foc_len, 'm') + #print(ipStartTr + 1, npDataTr + 1) + + for i in range(ipStartTr + 1, npDataTr + 1): + #for i in range(ipStartTr + 1, npDataTr): + if _ar_arg_tr is None: x2 = _height_prof_data[i][0] + else: x2 = _ar_arg_tr[i - 1] + + if((x1 <= x) and (x < x2)): + ipStartTr = i - 1 + #print(ix, iy, x1, x, x2) + break + #print(ix, i, x1, x2, x) + x1 = x2 + + elif('x' in _dim): + if(ix == 0): ipStart = 1 + + #x1 = argHeightProfData[ipStart]*sinAngR + if _ar_arg_long is None: x1 = _height_prof_data[0][ipStart]*sinAngR + else: x1 = _ar_arg_long[ipStart - 1]*sinAngR + + for i in range(ipStart + 1, npData + 1): + #for i in range(ipStart + 1, npData): + #x2 = argHeightProfData[i]*sinAngR + if _ar_arg_long is None: x2 = _height_prof_data[0][i]*sinAngR + else: x2 = _ar_arg_long[i - 1]*sinAngR + + if((x1 <= x) and (x < x2)): + ipStart = i - 1 + break + x1 = x2 - fx = 1e+23 - fy = 1e+23 - if(_foc_plane != 1): - fy = foc_len - if(_foc_plane != 2): - fx = foc_len + if _ar_arg_long is not None: ipStart -= 1 + if _ar_arg_tr is not None: ipStartTr -= 1 + + #Bi-Linear Interpolation + xt = 0; yt = 0 + f10 = 0; f01 = 0; f11 = 0 + if(x2 != x1): + xt = (x - x1)/(x2 - x1) + if('x' in _dim): + f10 = _height_prof_data[ipStartTr][ipStart+1] + else: + f10 = _height_prof_data[ipStartTr+1][ipStart] + if(y2 != y1): + yt = (y - y1)/(y2 - y1) + if('y' in _dim): + f01 = _height_prof_data[ipStartTr][ipStart+1] + else: + #OC_TEST + #print('ipStartTr=', ipStartTr, 'ipStart=', ipStart) + f01 = _height_prof_data[ipStartTr+1][ipStart] + if((x2 != x1) and (y2 != y1)): f11 = _height_prof_data[ipStartTr+1][ipStart+1] + + f00 = _height_prof_data[ipStartTr][ipStart] + #f10 = heightProfData[ipStartTr+1][ipStart] + #f01 = heightProfData[ipStartTr][ipStart+1] + #f11 = heightProfData[ipStartTr+1][ipStart+1] + a01 = f01 - f00 + a10 = f10 - f00 + a11 = f00 - f01 - f10 + f11 + hApprox = xt*(a10 + a11*yt) + a01*yt + f00 + + #print(' x:', x1, x, x2, 'y:', y1, y, y2) + #print('h:', hApprox, f00, f10, f01, f11, 'ii:', ipStartTr, ipStart) + #print(' ') + + ofst = 2*ix + (2*auxMesh.nx)*iy + optSlopeErr.arTr[ofst] = 1. #Amplitude Transmission + optSlopeErr.arTr[ofst + 1] = 0. #Optical Path Difference + if(hApprox != 0): + #optSlopeErr.arTr[ofst + 1] = -2*sinAng*hApprox #Optical Path Difference (to check sign!) + optSlopeErr.arTr[ofst + 1] = -(sinAng + sinAngR)*hApprox*_amp_coef #Optical Path Difference (to check sign!) + #print(ix, iy, optSlopeErr.arTr[ofst + 1]) + x += xStep + y += yStep + + optSlopeErr.input_parms = input_parms #MR26022016 + return optSlopeErr + +#**************************************************************************** +def srwl_opt_setup_gen_transm(_func_path_dif, _delta, _atten_len, _rx, _ry, _xc=0, _yc=0, _ext_tr=0, _fx=0, _fy=0, _e_start=0, _e_fin=0, _nx=1001, _ny=1001): + """ + Setup Transmission type Optical Element similar to one simulating CRL, but with arbitrary optical path difference over hor. and vert. positions, defined by external function _func_path_dif(x, y) + :param _func_path_dif: user-defined function of 2 variables specifying optical path difference over hor. and vert. positions (x, y) + :param _delta: refractive index decrement (can be one number of array vs photon energy) + :param _atten_len: attenuation length [m] (can be one number of array vs photon energy) + :param _rx: horizontal aperture (range) size [m] + :param _ry: vertical aperture (range) size [m] + :param _xc: horizontal coordinate of center [m] + :param _yc: vertical coordinate of center [m] + :param _ext_tr: transmission outside the grid/mesh is zero (0), or it is same as on boundary (1) + :param _fx: horizontal focal length [m]; if it is not set, a numerical estimate will be made (around _xc, _yc) + :param _fy: vertical focal length [m]; if it is not set, a numerical estimate will be made (around _xc, _yc) + :param _e_start: initial photon energy + :param _e_fin: final photon energy + :param _nx: number of points vs horizontal position to represent the transmission element + :param _ny: number of points vs vertical position to represent the transmission element + :return: transmission (SRWLOptT) type optical element which simulates CRL + """ - rx = _apert_h*1.1 - ry = _apert_v*1.1 - nx = 1001 - ny = 1001 ne = 1 arDelta = [0] arAttenLen = [0] @@ -1176,325 +4967,198 @@ def ray_path_in_spheres(_x, _y, _void_cen_rad): else: arDelta[0] = _delta arAttenLen[0] = _atten_len - - opT = SRWLOptT(nx, ny, rx, ry, None, 1, fx, fy, _xc, _yc, ne, _e_start, _e_fin) - halfApert = 0.5*_apert_h - halfApertV = 0.5*_apert_v + dx = _rx/(_nx - 1) + dy = _ry/(_ny - 1) - if(_foc_plane == 2): #1D lens, vertical is focusing plane - halfApert = halfApertV - elif(_foc_plane == 3): #2D lens - if(halfApert > halfApertV): - halfApert = halfApertV - - hx = rx/(nx - 1) - hy = ry/(ny - 1) + nTot = 2*ne*_nx*_ny #total array length to store amplitude transmission and optical path difference + arLocTr = array('d', [0]*nTot) + #Same data alignment as for wavefront: outmost loop vs y, inmost loop vs e ofst = 0 - y = -0.5*ry #CRL is always centered on the grid, however grid can be shifted - for iy in range(ny): - x = -0.5*rx - for ix in range(nx): - pathInBody = _n*ray_path_in_one_CRL(x, y, _foc_plane, _shape, halfApert, _r_min, _wall_thick) - - if(_void_cen_rad != None): #eventually subtract path in voids - pathInBody -= ray_path_in_spheres(x, y, _void_cen_rad) - + y = -0.5*_ry #CRL is always centered on the grid, however grid can be shifted + for iy in range(_ny): + x = -0.5*_rx + for ix in range(_nx): + pathDif = _func_path_dif(x, y) for ie in range(ne): - opT.arTr[ofst] = exp(-0.5*pathInBody/arAttenLen[ie]) #amplitude transmission - opT.arTr[ofst + 1] = -arDelta[ie]*pathInBody #optical path difference + arLocTr[ofst] = exp(-0.5*pathDif/arAttenLen[ie]) #amplitude transmission + arLocTr[ofst + 1] = -arDelta[ie]*pathDif #optical path difference ofst += 2 - x += hx - y += hy - return opT + x += dx + y += dy + + #Estimating focal lengths + fx = _fx + fy = _fy + avgDelta = arDelta[int(0.5*ne)] + if(avgDelta != 0): + if(fx == 0): + fm1 = _func_path_dif(_xc - dx, _yc) + f0 = _func_path_dif(_xc, _yc) + f1 = _func_path_dif(_xc + dx, _yc) + dfdx = 0.5*(f1 - fm1)/dx + d2fdx2 = (fm1 - 2*f0 + f1)/(dx*dx) + fx = 1.e+23 + if(d2fdx2 != 0): + auxSqrt = sqrt(1 + dfdx*dfdx) + radCurvX = auxSqrt*auxSqrt*auxSqrt/d2fdx2 + #print('Estimated radCurvX:', radCurvX) + fx = radCurvX/avgDelta #see the formula for CRL + #print('Estimated Fx=', fx) + if(fy == 0): + fm1 = _func_path_dif(_xc, _yc - dy) + f0 = _func_path_dif(_xc, _yc) + f1 = _func_path_dif(_xc, _yc + dy) + dfdy = 0.5*(f1 - fm1)/dy + d2fdy2 = (fm1 - 2*f0 + f1)/(dy*dy) + fy = 1.e+23 + if(d2fdy2 != 0): + auxSqrt = sqrt(1 + dfdy*dfdy) + radCurvY = auxSqrt*auxSqrt*auxSqrt/d2fdy2 + fy = radCurvY/avgDelta #see the formula for CRL + #print('Estimated Fy=', fy) + + return SRWLOptT(_nx, _ny, _rx, _ry, arLocTr, _ext_tr, fx, fy, _xc, _yc, ne, _e_start, _e_fin) #**************************************************************************** -def srwl_opt_setup_cyl_fiber(_foc_plane, _delta_ext, _delta_core, _atten_len_ext, _atten_len_core, _diam_ext, _diam_core, _xc, _yc): - """ - Setup Transmission type Optical Element which simulates Cylindrical Fiber - :param _foc_plane: plane of focusing: 1- horizontal (i.e. fiber is parallel to vertical axis), 2- vertical (i.e. fiber is parallel to horizontal axis) - :param _delta_ext: refractive index decrement of extenal layer - :param _delta_core: refractive index decrement of core - :param _atten_len_ext: attenuation length [m] of external layer - :param _atten_len_core: attenuation length [m] of core - :param _diam_ext: diameter [m] of external layer - :param _diam_core: diameter [m] of core - :param _xc: horizontal coordinate of center [m] - :param _yc: vertical coordinate of center [m] - :return: transmission (SRWLOptT) type optical element which simulates Cylindrical Fiber - """ +class SRWLDet(object): + """Detector of Radiation""" - def ray_path_in_cyl(_dx, _diam): - r = 0.5*_diam - pathInCyl = 0 - if((_dx > -r) and (_dx < r)): - pathInCyl = 2*sqrt(r*r - _dx*_dx) - return pathInCyl + def __init__(self, _xStart=0, _xFin=0, _nx=1, _yStart=0, _yFin=0, _ny=1, _dx=0, _dy=0, _spec_eff=1, _eStart=0, _eFin=0, _ord_interp=1): #, _ne=1): #, _eff_e=False): + """ + :param _xStart: initial value of horizontal position [m] (/angle [rad]) + :param _xFin: final value of horizontal position [m] (/angle [rad]) + :param _nx: number of points vs horizontal position [m] (/angle [rad]) + :param _yStart: initial value of vertical position [m] (/angle [rad]) + :param _yFin: final value of vertical position [m] (/angle [rad]) + :param _ny: number of points vs vertical position [m] (/angle [rad]) + :param _dx: horizontal pixel size [m] (/angle [rad]) + :param _dy: vertical pixel size [m] (/angle [rad]) + :param _spec_eff: one number or array defining detector spectral efficiency (as function of photon energy, on the mesh given by _eStart, _eFin, _ne) + :param _eStart: initial value of photon energy [eV] (/time [s]) + :param _eFin: final value of photon energy [eV] (/time [s]) + :param _ne: number of points vs photon energy [eV] (/time [s]) + :param _eff_e: treat spectral efficiency as for electric field if True + :param _ord_interp: interpolation order (i.e. order of polynomials to be used at 2D interpolation) + """ + self.xStart = _xStart + self.xFin = _xFin + self.nx = _nx + self.yStart = _yStart + self.yFin = _yFin + self.ny = _ny + self.dx = _dx + self.dy = _dy + self.specEff = _spec_eff + self.eStartEff = _eStart + self.eFinEff = _eFin + self.ord_interp = _ord_interp - ne = 1 - nx = 101 - ny = 1001 - rx = 10e-03 - ry = _diam_ext*1.2 - if(_foc_plane == 1): #focusing plane is horizontal - nx = 1001 - ny = 101 - rx = _diam_ext*1.2 - ry = 10e-03 + ne = 1 + if(isinstance(_spec_eff, list) or isinstance(_spec_eff, array)): ne = len(_spec_eff) + self.neEff = ne - opT = SRWLOptT(nx, ny, rx, ry, None, 1, 1e+23, 1e+23, _xc, _yc) + self.eStepEff = 0 if(ne <= 1) else (_eFin - _eStart)/ne - hx = rx/(nx - 1) - hy = ry/(ny - 1) - ofst = 0 - pathInExt = 0 - pathInCore = 0 + def treat_int(self, _stk, _mesh=None, _ord_interp=0): + """Treat Intensity of Input Radiation + :param _stk: Stokes data structure or a simple Intensity array to be treated by detector + :param _mesh: mesh structure (if it is defined, _stk should be treated as Intensity array of type f) + :param _ord_interp: Interpolation order to be used (overrides self.ord_interp) + """ + #Move this function to C in the future? - if(_foc_plane == 2): #focusing plane is vertical - y = -0.5*ry #cylinder is always centered on the grid, however grid can be shifted - for iy in range(ny): - pathInExt = 0; pathInCore = 0 - if(_diam_core > 0): - pathInCore = ray_path_in_cyl(y, _diam_core) - pathInExt = ray_path_in_cyl(y, _diam_ext) - pathInCore - argAtten = -0.5*pathInExt/_atten_len_ext - if(_atten_len_core > 0): - argAtten -= 0.5*pathInCore/_atten_len_core - ampTr = exp(argAtten) #amplitude transmission - optPathDif = -_delta_ext*pathInExt - _delta_core*pathInCore #optical path difference - for ix in range(nx): - opT.arTr[ofst] = ampTr #amplitude transmission - opT.arTr[ofst + 1] = optPathDif #optical path difference - ofst += 2 - y += hy - else: #focusing plane is horizontal - perY = 2*nx - x = -0.5*rx #cylinder is always centered on the grid, however grid can be shifted - for ix in range(nx): - pathInExt = 0; pathInCore = 0 - if(_diam_core > 0): - pathInCore = ray_path_in_cyl(x, _diam_core) - pathInExt = ray_path_in_cyl(x, _diam_ext) - pathInCore - argAtten = -0.5*pathInExt/_atten_len_ext - if(_atten_len_core > 0): - argAtten -= 0.5*pathInCore/_atten_len_core - ampTr = exp(argAtten) #amplitude transmission - optPathDif = -_delta_ext*pathInExt - _delta_core*pathInCore #optical path difference - ix2 = ix*2 - for iy in range(ny): - ofst = iy*perY + ix2 - opT.arTr[ofst] = ampTr #amplitude transmission - opT.arTr[ofst + 1] = optPathDif #optical path difference - x += hx - return opT + resInt = SRWLStokes(1, 'f', self.eStartEff, self.eFinEff, 1, self.xStart, self.xFin, self.nx, self.yStart, self.yFin, self.ny) + + meshIn = None + sktIn = None + if(_mesh is not None) and (isinstance(_mesh, SRWLRadMesh)): + meshIn = _mesh + arI = None + if(isinstance(_stk, array) and (_stk.itemsize == 4)): #array of type f + arI = _stk + else: + nTot = meshIn.ne*meshIn.nx*meshIn.ny + arI = array('f', [0]*nTot) + for i in range(nTot): arI[i] = _stk[i] + + sktIn = SRWLStokes(arI, 'f', meshIn.eStart, meshIn.eFin, meshIn.ne, meshIn.xStart, meshIn.xFin, meshIn.nx, meshIn.yStart, meshIn.yFin, meshIn.ny) + else: + if(not isinstance(_stk, SRWLStokes)): raise Exception('An object of SRWLStokes class is expected') + meshIn = _stk.mesh + #extMeshIsDef = True + + eRange = meshIn.eFin - meshIn.eStart + eStep = 0 if(meshIn.ne <= 1) else eRange/(meshIn.ne - 1) + bwMult = 1 if(eRange == 0) else 1./eRange + ePh = meshIn.eStart + for ie in range(meshIn.ne): + effMult = 1 #To treat Spectral Efficiency + if(self.specEff is not None): + if(isinstance(self.specEff, list) or isinstance(self.specEff, array)): + effMult = interp_1d(ePh, self.eStartEff, self.eStepEff, self.neEff, self.specEff, _ord=2) + else: effMult = self.specEff + + if((self.dx <= 0) or (self.dy <= 0)): + ordInterp = _ord_interp if(_ord_interp > 0) else self.ord_interp + resInt.avg_update_interp(sktIn, _iter=0, _ord=ordInterp, _n_stokes_comp=1, _mult=effMult*bwMult) #to treat all Stokes components / Polarization in the future + #else: + #Program integration within pixels self.dx, self.dy here + ePh += eStep + + return resInt + + def get_mesh(self): + eAvg = 0.5*(self.eStartEff + self.eFinEff) #? + return SRWLRadMesh( + _eStart=eAvg, _eFin=eAvg, _ne=1, + _xStart=self.xStart, _xFin=self.xFin, _nx=self.nx, + _yStart=self.yStart, _yFin=self.yFin, _ny=self.ny) #**************************************************************************** #**************************************************************************** #Auxiliary utility functions #**************************************************************************** #**************************************************************************** -def srwl_uti_interp_1d(_x, _x_min, _x_step, _nx, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): - """ - Interpolate 1D function value tabulated on equidistant mesh, using polynomial interpolation - :param _x: argument at which function value should be calculated - :param _x_min: minimal argument value of the tabulated function - :param _x_step: step of mesh at which function is tabulated - :param _nx: number of points in mesh at which function is tabulated - :param _ar_f: tabulated function list or array - :param _ord: order of polynomial interpolation (1- linear, 2- quadratic, 3- cubic) - :param _ix_per: argument index period of function data alignment (e.g. to interpolate one component of complex data, or in one dimension of multi-dimensional data) - :param _ix_ofst: argument index offset of function data alignment - :return: function value found by polynomial interpolation - """ - if(_ord == 1): - i0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) - if(i0 < 0): - i0 = 0 - elif(i0 >= _nx - 1): - i0 = _nx - 2 - i1 = i0 + 1 - f0 = _ar_f[i0*_ix_per + _ix_ofst] - f1 = _ar_f[i1*_ix_per + _ix_ofst] - t = (_x - (_x_min + _x_step*i0))/_x_step - return f0 + (f1 - f0)*t - elif(_ord == 2): - i0 = int(round((_x - _x_min)/_x_step)) - if(i0 < 1): - i0 = 1 - elif(i0 >= _nx - 1): - i0 = _nx - 2 - im1 = i0 - 1 - i1 = i0 + 1 - t = (_x - (_x_min + _x_step*i0))/_x_step - a0 = _ar_f[i0*_ix_per + _ix_ofst] - fm1 = _ar_f[im1*_ix_per + _ix_ofst] - f1 = _ar_f[i1*_ix_per + _ix_ofst] - a1 = 0.5*(f1 - fm1) - a2 = 0.5*(fm1 + f1 - 2*a0) - return a0 + t*(a1 + t*a2) - elif(_ord == 3): - i0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) - if(i0 < 1): - i0 = 1 - elif(i0 >= _nx - 2): - i0 = _nx - 3 - im1 = i0 - 1 - i1 = i0 + 1 - i2 = i0 + 2 - t = (_x - (_x_min + _x_step*i0))/_x_step - a0 = _ar_f[i0*_ix_per + _ix_ofst] - fm1 = _ar_f[im1*_ix_per + _ix_ofst] - f1 = _ar_f[i1*_ix_per + _ix_ofst] - f2 = _ar_f[i2*_ix_per + _ix_ofst] - a1 = -0.5*a0 + f1 - f2/6. - fm1/3. - a2 = -a0 + 0.5*(f1 + fm1) - a3 = 0.5*(a0 - f1) + (f2 - fm1)/6. - return a0 + t*(a1 + t*(a2 + t*a3)) - return 0 +#Moved to uti_math.py: +##def srwl_uti_interp_1d(_x, _x_min, _x_step, _nx, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): +##def srwl_uti_interp_2d(_x, _y, _x_min, _x_step, _nx, _y_min, _y_step, _ny, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): #**************************************************************************** -def srwl_uti_interp_2d(_x, _y, _x_min, _x_step, _nx, _y_min, _y_step, _ny, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): - """ - Interpolate 2D function value tabulated on equidistant rectangular mesh and represented by C-aligned flat array, using polynomial interpolation - :param _x: first argument at which function value should be calculated - :param _y: second argument at which function value should be calculated - :param _x_min: minimal value of the first argument of the tabulated function - :param _x_step: step of the first argument at which function is tabulated - :param _nx: number of points vs first argument at which function is tabulated - :param _y_min: minimal value of the second argument of the tabulated function - :param _y_step: step of the second argument at which function is tabulated - :param _ny: number of points vs second argument at which function is tabulated - :param _ar_f: function tabulated on 2D mesh, aligned as "flat" C-type list or array (first argument is changing most frequently) - :param _ord: "order" of polynomial interpolation (1- bi-linear (on 4 points), 2- "bi-quadratic" (on 6 points), 3- "bi-cubic" (on 12 points)) - :param _ix_per: period of first argument index of the function data alignment (e.g. to interpolate one component of complex data, or in one dimension of multi-dimensional data) - :param _ix_ofst: offset of the first argument index in function data alignment - :return: function value found by 2D polynomial interpolation +def srwl_uti_ph_en_conv(_x, _in_u='keV', _out_u='nm'): + """Photon Energy <-> Wavelength conversion + :param _x: value to be converted + :param _in_u: input unit + :param _out_u: output unit + :return: value in the output units """ - if(_ord == 1): #bi-linear interpolation based on 4 points - ix0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) - if(ix0 < 0): - ix0 = 0 - elif(ix0 >= _nx - 1): - ix0 = _nx - 2 - ix1 = ix0 + 1 - tx = (_x - (_x_min + _x_step*ix0))/_x_step - - iy0 = int(trunc((_y - _y_min)/_y_step + 1.e-09)) - if(iy0 < 0): - iy0 = 0 - elif(iy0 >= _ny - 1): - iy0 = _ny - 2 - iy1 = iy0 + 1 - ty = (_y - (_y_min + _y_step*iy0))/_y_step - - nx_ix_per = _nx*_ix_per - iy0_nx_ix_per = iy0*nx_ix_per - iy1_nx_ix_per = iy1*nx_ix_per - ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst - ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst - a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] - f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] - f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] - f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] - a10 = f10 - a00 - a01 = f01 - a00 - a11 = a00 - f01 - f10 + f11 - return a00 + tx*(a10 + ty*a11) + ty*a01 - - elif(_ord == 2): #bi-quadratic interpolation based on 6 points - ix0 = int(round((_x - _x_min)/_x_step)) - if(ix0 < 1): - ix0 = 1 - elif(ix0 >= _nx - 1): - ix0 = _nx - 2 - ixm1 = ix0 - 1 - ix1 = ix0 + 1 - tx = (_x - (_x_min + _x_step*ix0))/_x_step - - iy0 = int(round((_y - _y_min)/_y_step)) - if(iy0 < 1): - iy0 = 1 - elif(iy0 >= _ny - 1): - iy0 = _ny - 2 - iym1 = iy0 - 1 - iy1 = iy0 + 1 - ty = (_y - (_y_min + _y_step*iy0))/_y_step - - nx_ix_per = _nx*_ix_per - iym1_nx_ix_per = iym1*nx_ix_per - iy0_nx_ix_per = iy0*nx_ix_per - iy1_nx_ix_per = iy1*nx_ix_per - ixm1_ix_per_p_ix_ofst = ixm1*_ix_per + _ix_ofst - ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst - ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst - fm10 = _ar_f[iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst] - a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] - f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] - f0m1 = _ar_f[iym1_nx_ix_per + ix0_ix_per_p_ix_ofst] - f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] - f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] - a10 = 0.5*(f10 - fm10) - a01 = 0.5*(f01 - f0m1) - a11 = a00 - f01 - f10 + f11 - a20 = 0.5*(f10 + fm10) - a00 - a02 = 0.5*(f01 + f0m1) - a00 - return a00 + tx*(a10 + tx*a20 + ty*a11) + ty*(a01 + ty*a02) - - elif(_ord == 3): #bi-cubic interpolation based on 12 points - ix0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) - if(ix0 < 1): - ix0 = 1 - elif(ix0 >= _nx - 2): - ix0 = _nx - 3 - ixm1 = ix0 - 1 - ix1 = ix0 + 1 - ix2 = ix0 + 2 - tx = (_x - (_x_min + _x_step*ix0))/_x_step - - iy0 = int(trunc((_y - _y_min)/_y_step + 1.e-09)) - if(iy0 < 1): - iy0 = 1 - elif(iy0 >= _ny - 2): - iy0 = _ny - 3 - iym1 = iy0 - 1 - iy1 = iy0 + 1 - iy2 = iy0 + 2 - ty = (_y - (_y_min + _y_step*iy0))/_y_step - - nx_ix_per = _nx*_ix_per - iym1_nx_ix_per = iym1*nx_ix_per - iy0_nx_ix_per = iy0*nx_ix_per - iy1_nx_ix_per = iy1*nx_ix_per - iy2_nx_ix_per = iy2*nx_ix_per - ixm1_ix_per_p_ix_ofst = ixm1*_ix_per + _ix_ofst - ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst - ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst - ix2_ix_per_p_ix_ofst = ix2*_ix_per + _ix_ofst - f0m1 = _ar_f[iym1_nx_ix_per + ix0_ix_per_p_ix_ofst] - f1m1 = _ar_f[iym1_nx_ix_per + ix1_ix_per_p_ix_ofst] - fm10 = _ar_f[iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst] - a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] - f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] - f20 = _ar_f[iy0_nx_ix_per + ix2_ix_per_p_ix_ofst] - fm11 = _ar_f[iy1_nx_ix_per + ixm1_ix_per_p_ix_ofst] - f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] - f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] - f21 = _ar_f[iy1_nx_ix_per + ix2_ix_per_p_ix_ofst] - f02 = _ar_f[iy2_nx_ix_per + ix0_ix_per_p_ix_ofst] - f12 = _ar_f[iy2_nx_ix_per + ix1_ix_per_p_ix_ofst] - a10 = -0.5*a00 + f10 - f20/6 - fm10/3 - a01 = -0.5*a00 + f01 - f02/6 - f0m1/3 - a11 = -0.5*(f01 + f10) + (f02 - f12 + f20 - f21)/6 + (f0m1 - f1m1 + fm10 - fm11)/3 + f11 - a20 = -a00 + 0.5*(f10 + fm10) - a02 = -a00 + 0.5*(f01 + f0m1) - a21 = a00 - f01 + 0.5*(f11 - f10 - fm10 + fm11) - a12 = a00 - f10 + 0.5*(f11 - f01 - f0m1 + f1m1) - a30 = 0.5*(a00 - f10) + (f20 - fm10)/6 - a03 = 0.5*(a00 - f01) + (f02 - f0m1)/6 - a31 = 0.5*(f01 + f10 - f11 - a00) + (f21 + fm10 - f20 - fm11)/6 - a13 = 0.5*(f10 - f11 - a00 + f01) + (f0m1 + f12 - f02 - f1m1)/6 - return a00 + tx*(a10 + tx*(a20 + tx*(a30 + ty*a31) + ty*a21) + ty*a11) + ty*(a01 + ty*(a02 + ty*(a03 + tx*a13) + tx*a12)) - return 0 + #convert _in_u -> [keV]: + x_keV = _x + if _in_u == 'eV': x_keV *= 1.e-03 + elif _in_u == '1/cm': x_keV *= (_Light_eV_mu*1.e-07) + elif _in_u == 'A': x_keV = 10*_Light_eV_mu/x_keV + elif _in_u == 'nm': x_keV = _Light_eV_mu/x_keV + elif _in_u == 'um': x_keV = (_Light_eV_mu*1.e-03)/x_keV #this had to be modofoed because of non-ascii "mu" symbol that did not compile on Py 2.7 + elif _in_u == 'mm': x_keV = (_Light_eV_mu*1.e-06)/x_keV + elif _in_u == 'm': x_keV = (_Light_eV_mu*1.e-09)/x_keV + elif _in_u == 'THz': x_keV *= (_Light_eV_mu*1000./_LightSp) #sinp="THz";outputval=val*(4.1356672e-06) + #convert [keV] -> _out_u: + x = x_keV + if _out_u == 'eV': x *= 1000. + elif _out_u == '1/cm': x /= (_Light_eV_mu*1.e-07) + elif _out_u == 'A': x = 10*_Light_eV_mu/x + elif _out_u == 'nm': x = _Light_eV_mu/x + elif _out_u == 'um': x = (_Light_eV_mu*1.e-03)/x #this had to be modifoed because of non-ascii "mu" symbol that did not compile on Py 2.7 + elif _out_u == 'mm': x = (_Light_eV_mu*1.e-06)/x + elif _out_u == 'm': x = (_Light_eV_mu*1.e-09)/x + elif _out_u == 'THz': x /= (_Light_eV_mu*1000./_LightSp) #sout="THz";outputval=outputval/(4.1356672e-06) + return x + +#**************************************************************************** +def srwl_uti_num_round(_x, _ndig=8): + order = round(log10(_x)) + fact = 10**order + return round(_x/fact, _ndig)*fact #**************************************************************************** def srwl_uti_rand_fill_vol(_np, _x_min, _x_max, _nx, _ar_y_vs_x_min, _ar_y_vs_x_max, _y_min, _y_max, _ny, _ar_z_vs_xy_min, _ar_z_vs_xy_max): @@ -1511,7 +5175,7 @@ def srwl_uti_rand_fill_vol(_np, _x_min, _x_max, _nx, _ar_y_vs_x_min, _ar_y_vs_x_ :param _ny: number of points vs y coord. :param _ar_z_vs_xy_min: min. z vs x and y flat 2D array :param _ar_z_vs_xy_max: max. z vs x and y flat 2D array - :returns: flat array of point coordinates: array('d', [x1,y1,z1,x2,y2,z2,...]) + :return: flat array of point coordinates: array('d', [x1,y1,z1,x2,y2,z2,...]) """ yMin = _ar_y_vs_x_min[0] yMax = _ar_y_vs_x_max[0] @@ -1549,12 +5213,17 @@ def srwl_uti_rand_fill_vol(_np, _x_min, _x_max, _nx, _ar_y_vs_x_min, _ar_y_vs_x_ for i in range(_np): x = xCen + xRange*(random.random() - 0.5) y = yCen + yRange*(random.random() - 0.5) - yTestMin = srwl_uti_interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_min) - yTestMax = srwl_uti_interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_max) + #yTestMin = srwl_uti_interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_min) + yTestMin = uti_math.interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_min) + #yTestMax = srwl_uti_interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_max) + yTestMax = uti_math.interp_1d(x, _x_min, xStep, _nx, _ar_y_vs_x_max) + if((y >= yTestMin) and (y <= yTestMax)): z = zCen + zRange*(random.random() - 0.5) - zTestMin = srwl_uti_interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_min) - zTestMax = srwl_uti_interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_max) + #zTestMin = srwl_uti_interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_min) + zTestMin = uti_math.interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_min) + #zTestMax = srwl_uti_interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_max) + zTestMax = uti_math.interp_2d(x, y, _x_min, xStep, _nx, _y_min, yStep, _ny, _ar_z_vs_xy_max) if((z >= zTestMin) and (z <= zTestMax)): ofst = iPtCount*3 arPtCoord[ofst] = x @@ -1578,9 +5247,13 @@ def srwl_uti_proc_is_master(): Check if process is Master (in parallel processing sense) """ try: - resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], -1) #MPI module dynamic load - #multiply re-import won't hurt; but it would be better to avoid this(?) - MPI = resImpMPI4Py.MPI + ##resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], -1) #MPI module dynamic load + #resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], 0) #MPI module dynamic load + ##multiple re-import won't hurt; but it would be better to avoid this(?) + #MPI = resImpMPI4Py.MPI + + from mpi4py import MPI #OC091014 + comMPI = MPI.COMM_WORLD rankMPI = comMPI.Get_rank() if(rankMPI == 0): @@ -1590,37 +5263,599 @@ def srwl_uti_proc_is_master(): except: return True -#**********************Auxiliary function to write tabulated resulting Intensity data to ASCII file: -def srwl_uti_save_intens_ascii(_ar_intens, _mesh, _file_path, _n_stokes=1): +#**********************Auxiliary function to write tabulated resulting Intensity data to an ASCII file: +def srwl_uti_save_intens_ascii(_ar_intens, _mesh, _file_path, _n_stokes=1, _arLabels=['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Intensity'], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2'], _mutual=0, _cmplx=0): #OC06052018 +#def srwl_uti_save_intens_ascii(_ar_intens, _mesh, _file_path, _n_stokes=1, _arLabels=['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Intensity'], _arUnits=['eV', 'm', 'm', 'ph/s/.1%bw/mm^2'], _mutual=0): f = open(_file_path, 'w') - f.write('#C-aligned Intensity (inner loop is vs photon energy, outer loop vs vertical position)\n') - f.write('#' + repr(_mesh.eStart) + ' #Initial Photon Energy [eV]\n') - f.write('#' + repr(_mesh.eFin) + ' #Final Photon Energy [eV]\n') - f.write('#' + repr(_mesh.ne) + ' #Number of points vs Photon Energy\n') - f.write('#' + repr(_mesh.xStart) + ' #Initial Horizontal Position [m]\n') - f.write('#' + repr(_mesh.xFin) + ' #Final Horizontal Position [m]\n') - f.write('#' + repr(_mesh.nx) + ' #Number of points vs Horizontal Position\n') - f.write('#' + repr(_mesh.yStart) + ' #Initial Vertical Position [m]\n') - f.write('#' + repr(_mesh.yFin) + ' #Final Vertical Position [m]\n') - f.write('#' + repr(_mesh.ny) + ' #Number of points vs Vertical Position\n') - f.write('#' + repr(_n_stokes) + ' #Number of Stokes Components\n') - nVal = _mesh.ne*_mesh.nx*_mesh.ny*_n_stokes + arLabelUnit = [_arLabels[i] + ' [' + _arUnits[i] + ']' for i in range(4)] + + sUnitEnt = arLabelUnit[3] + + if(_mutual != 0): + sUnitEntParts = [''] + if((sUnitEnt is not None) and (len(sUnitEnt) > 0)): sUnitEntParts = sUnitEnt.split(' ') + sUnitEntTest = sUnitEnt + if(len(sUnitEntParts) > 0): sUnitEntTest = sUnitEntParts[0] + sUnitEntTest = sUnitEntTest.replace(' ', '') + if(sUnitEntTest.lower != 'mutual'): + sPrefix = 'Mutual' #this prefix is a switch meaning eventual special processing in viewing utilities + if(_cmplx != 0): sPrefix = 'Complex Mutual' #OC06052018 + if(sUnitEnt.startswith(' ') == False): sPrefix += ' ' + sUnitEnt = sPrefix + sUnitEnt + + #print(sUnitEnt) #DEBUG + + f.write('#' + sUnitEnt + ' (C-aligned, inner loop is vs ' + _arLabels[0] + ', outer loop vs ' + _arLabels[2] + ')\n') + f.write('#' + repr(_mesh.eStart) + ' #Initial ' + arLabelUnit[0] + '\n') + f.write('#' + repr(_mesh.eFin) + ' #Final ' + arLabelUnit[0] + '\n') + f.write('#' + repr(_mesh.ne) + ' #Number of points vs ' + _arLabels[0] + '\n') + f.write('#' + repr(_mesh.xStart) + ' #Initial ' + arLabelUnit[1] + '\n') + f.write('#' + repr(_mesh.xFin) + ' #Final ' + arLabelUnit[1] + '\n') + f.write('#' + repr(_mesh.nx) + ' #Number of points vs ' + _arLabels[1] + '\n') + f.write('#' + repr(_mesh.yStart) + ' #Initial ' + arLabelUnit[2] + '\n') + f.write('#' + repr(_mesh.yFin) + ' #Final ' + arLabelUnit[2] + '\n') + f.write('#' + repr(_mesh.ny) + ' #Number of points vs ' + _arLabels[2] + '\n') + + #strOut = '#' + sUnitEnt + ' (C-aligned, inner loop is vs ' + _arLabels[0] + ', outer loop vs ' + _arLabels[2] + ')\n' + #strOut += '#' + repr(_mesh.eStart) + ' #Initial ' + arLabelUnit[0] + '\n' + #strOut += '#' + repr(_mesh.eFin) + ' #Final ' + arLabelUnit[0] + '\n' + #strOut += '#' + repr(_mesh.ne) + ' #Number of points vs ' + _arLabels[0] + '\n' + #strOut += '#' + repr(_mesh.xStart) + ' #Initial ' + arLabelUnit[1] + '\n' + #strOut += '#' + repr(_mesh.xFin) + ' #Final ' + arLabelUnit[1] + '\n' + #strOut += '#' + repr(_mesh.nx) + ' #Number of points vs ' + _arLabels[1] + '\n' + #strOut += '#' + repr(_mesh.yStart) + ' #Initial ' + arLabelUnit[2] + '\n' + #strOut += '#' + repr(_mesh.yFin) + ' #Final ' + arLabelUnit[2] + '\n' + #strOut += '#' + repr(_mesh.ny) + ' #Number of points vs ' + _arLabels[2] + '\n' + + nComp = 1 + if _n_stokes > 0: + f.write('#' + repr(_n_stokes) + ' #Number of components\n') + #strOut += '#' + repr(_n_stokes) + ' #Number of components\n' + nComp = _n_stokes + nRadPt = _mesh.ne*_mesh.nx*_mesh.ny + if(_mutual > 0): nRadPt *= nRadPt + + nVal = nRadPt*nComp #_mesh.ne*_mesh.nx*_mesh.ny*nComp + if(_cmplx != 0): nVal *= 2 #OC06052018 + for i in range(nVal): #write all data into one column using "C-alignment" as a "flat" 1D array f.write(' ' + repr(_ar_intens[i]) + '\n') + #strOut += ' ' + repr(_ar_intens[i]) + '\n' + + #f = open(_file_path, 'w') + #f.write(strOut) + f.close() + +#**********************Auxiliary function to read-in tabulated Intensity data from an ASCII file (format is defined in srwl_uti_save_intens_ascii) +def srwl_uti_read_intens_ascii(_file_path, _num_type='f'): + + sCom = '#' + f = open(_file_path, 'r') + lines = f.readlines() + + resMesh = SRWLRadMesh() + + curParts = lines[1].split(sCom); resMesh.eStart = float(curParts[1]) #to check + curParts = lines[2].split(sCom); resMesh.eFin = float(curParts[1]) #to check + curParts = lines[3].split(sCom); resMesh.ne = int(curParts[1]) #to check + + curParts = lines[4].split(sCom); resMesh.xStart = float(curParts[1]) #to check + curParts = lines[5].split(sCom); resMesh.xFin = float(curParts[1]) #to check + curParts = lines[6].split(sCom); resMesh.nx = int(curParts[1]) #to check + + curParts = lines[7].split(sCom); resMesh.yStart = float(curParts[1]) #to check + curParts = lines[8].split(sCom); resMesh.yFin = float(curParts[1]) #to check + curParts = lines[9].split(sCom); resMesh.ny = int(curParts[1]) #to check + + iStart = 10 + if((lines[10])[0] == sCom): iStart = 11 + + nRows = len(lines) + arInt = [] + for i in range(iStart, nRows): + curLine = lines[i] + if(len(curLine) > 0): arInt.append(float(curLine)) + f.close() + return array(_num_type, arInt), resMesh + +#**********************Auxiliary function to write auxiliary/debugging information to an ASCII file: +##def srwl_uti_save_text(_text, _file_path): +## f = open(_file_path, 'w') +## f.write(_text + '\n') +## f.close() + +#def srwl_uti_save_text(_text, _file_path, mode='a', newline='\n'): #MR28092016 +def srwl_uti_save_text(_text, _file_path, mode='w', newline='\n'): #MR29092016 + with open(_file_path, mode) as f: + f.write(_text + newline) + +#**********************Auxiliary function to read-in data comumns from ASCII file (2D table): +def srwl_uti_read_data_cols(_file_path, _str_sep, _i_col_start=0, _i_col_end=-1, _n_line_skip=0): + """ + Auxiliary function to read-in data comumns from ASCII file (2D table) + :param _file_path: full path (including file name) to the file + :param _str_sep: column separation symbol(s) (string) + :param _i_col_start: initial data column to read + :param _i_col_end: final data column to read + :param _n_line_skip: number of lines to skip in the beginning of the file + :return: 2D list containing data columns read + """ + f = open(_file_path, 'r') + lines = f.readlines() + + resCols = [] + + #nCol = _i_col_end - _i_col_start + 1 + #for iCol in range(nCol): + # resCols.append([]) + + nRows = len(lines) - _n_line_skip + + for i in range(nRows): + curLine = lines[_n_line_skip + i] + curLineParts = curLine.split(_str_sep) + curNumParts = len(curLineParts) + #print(curLineParts) + + colCount = 0; colCountTrue = 0 + for iCol in range(curNumParts): + curPart = curLineParts[iCol] + #print(curPart) + + if(len(curPart) > 0): + if(((_i_col_start <= colCount) or (_i_col_start < 0)) and ((colCount <= _i_col_end) or (_i_col_end < 0))): + if len(resCols) < (colCountTrue + 1): resCols.append([]) + resCols[colCountTrue].append(float(curPart)) + colCountTrue += 1 + colCount += 1 + f.close() + return resCols #attn: returns lists, not arrays! + +#**********************Auxiliary function to write (save) data comumns to ASCII file (2D table): +def srwl_uti_write_data_cols(_file_path, _cols, _str_sep, _str_head=None, _i_col_start=0, _i_col_end=-1): + """ + Auxiliary function to write tabulated data (columns, i.e 2D table) to ASCII file + :param _file_path: full path (including file name) to the file to be (over-)written + :param _cols: array of data columns to be saves to file + :param _str_sep: column separation symbol(s) (string) + :param _str_head: header (string) to write before data columns + :param _i_col_start: initial data column to write + :param _i_col_end: final data column to write + """ + f = open(_file_path, 'w') + + if(_str_head is not None): + lenStrHead = len(_str_head) + if(lenStrHead > 0): + strHead = _str_head + if(_str_head[lenStrHead - 1] != '\n'): + strHead = copy(_str_head) + '\n' + f.write(strHead) + if(_cols is None): + f.close(); return + + nCols = len(_cols) + if(nCols <= 0): + f.close(); return + + nLines = len(_cols[0]) + for i in range(1, nCols): + newLen = len(_cols[i]) + if(nLines < newLen): nLines = newLen + + strSep = '\t' + if(_str_sep is not None): + if(len(_str_sep) > 0): strSep = _str_sep + + strTot = '' + iColEndP1 = nCols + if((_i_col_end >= 0) and (_i_col_end < nCols)): iColEndP1 = _i_col_end + 1 + iColEnd = iColEndP1 - 1 + nLinesM1 = nLines - 1 + + for i in range(nLines): + curLine = '' + for j in range(_i_col_start, iColEndP1): + curElem = ' ' + if(i < len(_cols[j])): curElem = repr(_cols[j][i]) + curLine += curElem + if(j < iColEnd): curLine += strSep + if(i < nLinesM1): curLine += '\n' + strTot += curLine + + f.write(strTot) + f.close() + +#**********************Auxiliary function to write auxiliary information about calculation status with "srwl_wfr_emit_prop_multi_e" to an ASCII files: +#def srwl_uti_save_status_mpi( # #MR20160908 +def srwl_uti_save_stat_wfr_emit_prop_multi_e( #MR20160908 + particle_number=0, + total_num_of_particles=0, + #filename='srw_mpi', + filename='srwl_stat_wfr_emit_prop_multi_e', #MR13012017 + cores=None, + particles_per_iteration=None +): + """The function to save .log and .json status files to monitor parallel MPI jobs progress. + + :param particle_number: current particle number. + :param total_num_of_particles: total number of particles. + :param filename: the name without extension used to save log/status files. + :param cores: number of cores used for parallel calculation. + :param particles_per_iteration: number of particles averaged per iteration (between mpi-receives).- + :return: None. + """ + offset = len(str(total_num_of_particles)) + timestamp = '{:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()) + progress = float(particle_number) / float(total_num_of_particles) * 100.0 + status = 'Running' if progress < 100.0 else 'Finished' + + # Save a log file to monitor duration of calculations: + mode = 'a' + if particle_number == 0: + mode = 'w' + text_to_save = '[{}]: Calculation on {} cores with averaging of {} particles/iteration.'.format( + timestamp, + cores, + particles_per_iteration, + ) + else: + text_to_save = '[{}]: {:8s} {:{offset}d} out of {:{offset}d} ({:6.2f}% complete)'.format( + timestamp, + status, + particle_number, + total_num_of_particles, + progress, + offset=offset, + ) + status_text_file = '{}.log'.format(filename) + srwl_uti_save_text(text_to_save, status_text_file, mode=mode) + + # Save JSON file for Sirepo: + status = { + 'timestamp': timestamp, + 'particle_number': particle_number, + 'total_num_of_particles': total_num_of_particles, + 'progress': progress, + 'status': status, + } + status_json_file = '{}.json'.format(filename) + #with open(status_json_file, 'w') as f: + # json.dump(status, f, indent=4, separators=(',', ': '), sort_keys=True) + #MR05122016: A temp file is created on the same filesystem as the status file to ensure the atomic rename operation: + # See the following discussions: + # - https://github.com/radiasoft/sirepo/issues/555 + # - https://github.com/radiasoft/SRW-light/commit/987547f4da3079626bef92aad2f9ca3bade84ada + # - http://stackoverflow.com/a/3716361/4143531 + tmp_file = tempfile.NamedTemporaryFile(delete=False, mode='w', dir=os.path.dirname(status_json_file)) + json.dump(status, tmp_file, indent=4, separators=(',', ': '), sort_keys=True) + tmp_file.close() + shutil.move(tmp_file.name, status_json_file) + +#**********************Auxiliary function to initialize parameters for the SRW status files and generate the files +def srwl_uti_save_stat_wfr_emit_prop_multi_e_init(rank, num_of_proc, num_part_per_proc, num_sent_per_proc, num_part_avg_proc): #MR20012017 + """Initialize parameters for the SRW status files and generate the files. + :param rank: rank of the process. + :param num_of_proc: total number of processes. + :param num_part_per_proc: number of electrons treated by each worker process. + :param num_sent_per_proc: number of sending acts made by each worker process. + :param num_part_avg_proc: number of macro-electrons to be used in calculation by each worker. + """ + log_dir = os.path.abspath('__srwl_logs__') + if rank == 0: + try: + os.mkdir(log_dir) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(log_dir): + pass + else: + raise + timestamp = '{:%Y-%m-%d_%H-%M-%S}'.format(datetime.datetime.now()) + log_file = 'srwl_stat_wfr_emit_prop_multi_e_{}'.format(timestamp) + log_path = os.path.join(log_dir, log_file) + if num_of_proc <= 1: + total_num_of_particles = num_part_per_proc + else: + total_num_of_particles = num_sent_per_proc * (num_of_proc - 1) * num_part_avg_proc + if rank == 0: + srwl_uti_save_stat_wfr_emit_prop_multi_e(0, total_num_of_particles, filename=log_path, cores=num_of_proc, particles_per_iteration=num_part_avg_proc) + return log_path, total_num_of_particles + +#**********************Auxiliary function to read tabulated 3D Magnetic Field data from ASCII file: +def srwl_uti_read_mag_fld_3d(_fpath, _scom='#'): + f = open(_fpath, 'r') + f.readline() #1st line: just pass + xStart = float(f.readline().split(_scom, 2)[1]) #2nd line: initial X position [m]; it will not actually be used + xStep = float(f.readline().split(_scom, 2)[1]) #3rd line: step vs X [m] + xNp = int(f.readline().split(_scom, 2)[1]) #4th line: number of points vs X + yStart = float(f.readline().split(_scom, 2)[1]) #5th line: initial Y position [m]; it will not actually be used + yStep = float(f.readline().split(_scom, 2)[1]) #6th line: step vs Y [m] + yNp = int(f.readline().split(_scom, 2)[1]) #7th line: number of points vs Y + zStart = float(f.readline().split(_scom, 2)[1]) #8th line: initial Z position [m]; it will not actually be used + zStep = float(f.readline().split(_scom, 2)[1]) #9th line: step vs Z [m] + zNp = int(f.readline().split(_scom, 2)[1]) #10th line: number of points vs Z + totNp = xNp*yNp*zNp + locArBx = array('d', [0]*totNp) + locArBy = array('d', [0]*totNp) + locArBz = array('d', [0]*totNp) + strSep = '\t' + for i in range(totNp): + curLineParts = f.readline().split(strSep) + #DEBUG + #print(i, curLineParts) + #END DEBUG + locArBx[i] = float(curLineParts[0]) + locArBy[i] = float(curLineParts[1]) + locArBz[i] = float(curLineParts[2]) f.close() + xRange = xStep + if xNp > 1: xRange = (xNp - 1)*xStep + yRange = yStep + if yNp > 1: yRange = (yNp - 1)*yStep + zRange = zStep + if zNp > 1: zRange = (zNp - 1)*zStep + + xc = xStart + 0.5*xStep*(xNp - 1) + yc = yStart + 0.5*yStep*(yNp - 1) + zc = zStart + 0.5*zStep*(zNp - 1) + return SRWLMagFldC(SRWLMagFld3D(locArBx, locArBy, locArBz, xNp, yNp, zNp, xRange, yRange, zRange, 1), xc, yc, zc) + +#**********************Auxiliary function to allocate array +#(to walk-around the problem that simple allocation "array(type, [0]*n)" at large n is usually very time-consuming) +def srwl_uti_array_alloc(_type, _n): + nPartMax = 10000000 #to tune + if(_n <= nPartMax): return array(_type, [0]*_n) + #resAr = array(_type, [0]*_n) + #print('Array requested:', _n, 'Allocated:', len(resAr)) + #return resAr + + nEqualParts = int(_n/nPartMax) + nResid = int(_n - nEqualParts*nPartMax) + resAr = array(_type, [0]*nPartMax) + if(nEqualParts > 1): + auxAr = deepcopy(resAr) + for i in range(nEqualParts - 1): resAr.extend(auxAr) + if(nResid > 0): + auxAr = array(_type, [0]*nResid) + resAr.extend(auxAr) + + #print('Array requested:', _n, 'Allocated:', len(resAr)) + return resAr + +#**********************Auxiliary function to generate Halton sequence (to replace pseudo-random numbers) +#Contribution from R. Lindberg, X. Shi (APS) +def srwl_uti_math_seq_halton(i, base=2): +#def Halton(i, base=2): + h = 0 + fac = 1.0/base + while i != 0: + digit = i % base + #h = h + digit*fac + h += digit*fac + i = (i - digit)/base + #fac = fac/base + fac /= base + return h #**************************************************************************** #**************************************************************************** #Wavefront manipulation functions #**************************************************************************** #**************************************************************************** -def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_part_tot, _n_part_avg_proc=1, _n_save_per=100, _file_path=None, _sr_samp_fact=-1, _opt_bl=None, _pres_ang=0): + +#**********************Auxiliary function to propagate wavefront over free space in a number of steps and extract resulting intensity cuts +def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0, _ry=0, _xc=0, _yc=0, _pol=6, _type=0, _ord_interp=1): + """ + Propagates wavefront over free space in a number of steps and generates intensity distributions vs (z,x) and (z,y) and possibly (z,x,y) + :param _wfr: input/output wavefront + :param _dz: longitudinal step size for the drifts + :param _nz: number of drift steps to be made + :param _pp: list of propagation parameters to be used for each drift step + :param _do3d: generate intensity vs (z,x,y) in addition to the cuts (z,x) and (z,y) + :param _nx: number of points vs horizontal position (is taken into account if >0) + :param _ny: number of points vs vertical position (is taken into account if >0) + :param _rx: number of points vs horizontal position (is taken into account if >0) + :param _ry: number of points vs vertical position(is taken into account if >0) + :param _xc: horizontal position for vertical cut of intensity + :param _yc: vertical position for horizontal cut of intensity + :param _pol: switch specifying polarization component to be extracted: + =0 -Linear Horizontal; + =1 -Linear Vertical; + =2 -Linear 45 degrees; + =3 -Linear 135 degrees; + =4 -Circular Right; + =5 -Circular Left; + =6 -Total + :param _type: switch specifying "type" of a characteristic to be extracted: + =0 -"Single-Electron" Intensity; + =1 -"Multi-Electron" Intensity; + =2 -"Single-Electron" Flux; + =3 -"Multi-Electron" Flux; + =4 -"Single-Electron" Radiation Phase; + =5 -Re(E): Real part of Single-Electron Electric Field; + =6 -Im(E): Imaginary part of Single-Electron Electric Field; + =7 -"Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence) + :param _ord_interp: interpolation order for final intensity calc. + :return resulting intensity distributions + """ + + if(_nx <= 0): _nx = _wfr.mesh.nx + if(_ny <= 0): _ny = _wfr.mesh.ny + + nzp1 = _nz + 1 + + resIntVsZX = array('f', [0]*(nzp1*_nx)) #array to store the final intensity + resIntVsZY = array('f', [0]*(nzp1*_ny)) #array to store the final intensity + resIntVsZXY = None + if(_do3d): resIntVsZXY = array('f', [0]*(nzp1*_nx*_ny)) #array to store the final intensity + + ec = _wfr.mesh.eStart + if(_wfr.mesh.ne > 1): ec = 0.5*(_wfr.mesh.eStart + _wfr.mesh.eFin) + + cntDrift = SRWLOptC([SRWLOptD(_dz)], [_pp]) + + xStart = _wfr.mesh.xStart + xFin = _wfr.mesh.xFin + if(_rx > 0): + halfRx = 0.5*_rx + xStart = _xc - halfRx + xFin = _xc + halfRx + xStep = (xFin - xStart)/(_nx - 1) if _nx > 1 else 0 + + yStart = _wfr.mesh.yStart + yFin = _wfr.mesh.yFin + if(_ry > 0): + halfRy = 0.5*_ry + yStart = _yc - halfRy + yFin = _yc + halfRy + yStep = (yFin - yStart)/(_ny - 1) if _ny > 1 else 0 + + for iz in range(0, nzp1): + + if(iz > 0): + print('Propagation (step # ' + repr(iz) + ') ... ', end='') + t0 = time.time(); + srwl.PropagElecField(_wfr, cntDrift) + print('completed (lasted', round(time.time() - t0, 6), 's)') + + curMesh = _wfr.mesh + xStepCurMesh = (curMesh.xFin - curMesh.xStart)/(curMesh.nx - 1) + yStepCurMesh = (curMesh.yFin - curMesh.yStart)/(curMesh.ny - 1) + curIntVsX = array('f', [0]*_wfr.mesh.nx) + curIntVsY = array('f', [0]*_wfr.mesh.ny) + + srwl.CalcIntFromElecField(curIntVsX, _wfr, _pol, _type, 1, ec, _xc, _yc) #int. vs X + + x = xStart + for ix in range(_nx): #interpolation + resIntVsZX[iz + ix*nzp1] = uti_math.interp_1d(x, curMesh.xStart, xStepCurMesh, curMesh.nx, curIntVsX, _ord_interp) + x += xStep + + srwl.CalcIntFromElecField(curIntVsY, _wfr, _pol, _type, 2, ec, _xc, _yc) #int. vs Y + + y = yStart + for iy in range(_ny): #interpolation + resIntVsZY[iz + iy*nzp1] = uti_math.interp_1d(y, curMesh.yStart, yStepCurMesh, curMesh.ny, curIntVsY, _ord_interp) + y += yStep + + if(_do3d): + curIntVsXY = array('f', [0]*_wfr.mesh.nx*_wfr.mesh.ny) + srwl.CalcIntFromElecField(curIntVsXY, _wfr, _pol, _type, 3, ec, _xc, _yc) #int. vs XY + + nxny = _nx*_ny + y = yStart + for iy in range(_ny): + x = xStart + for ix in range(_nx): + resIntVsZXY[ix + iy*_nx + iz*nxny] = uti_math.interp_2d(x, y, curMesh.xStart, xStepCurMesh, curMesh.nx, curMesh.yStart, yStepCurMesh, curMesh.ny, curIntVsXY, _ord_interp) + x += xStep + y += yStep + + resMesh = SRWLRadMesh(ec, ec, 1, xStart, xFin, _nx, yStart, yFin, _ny, 0.) + resMesh.zFin = _dz*_nz #adding long. mesh params (note: these may not propagate further!) + resMesh.nz = nzp1 #adding long. mesh params (may not propagate further!) + + return resIntVsZX, resIntVsZY, resIntVsZXY, resMesh + +#**********************Auxiliary function to setup Coherent Wavefront from Intensity (assuming spherical or astigmatic wave) +def srwl_wfr_from_intens(_ar_int, _mesh, _part_beam, _Rx, _Ry, _xc=0, _yc=0): + """ + Setup Coherent Wavefront from Intensity (assuming spherical or asigmatic wave): note this is an error-prone procedure + :param _ar_int: input intensity array + :param _mesh: mesh vs photon energy, horizontal and vertical positions (SRWLRadMesh type) on which initial SR should be calculated + :param _part_beam: Finite-Emittance beam (SRWLPartBeam type) + :param _Rx: horizontal wavefront radius [m] + :param _Ry: vertical wavefront radius [m] + :param _xc: horizontal wavefront center position [m] + :param _yc: vertical wavefront center position [m] + """ + + lenInt = len(_ar_int) + nTot = _mesh.ne*_mesh.nx*_mesh.ny + if(lenInt != nTot): + raise Exception("Mesh parameters are not consistent with the length of intensity array") + + aux_const = 3.14159265358979E+06/1.23984186 + constRx = aux_const/_Rx + constRy = aux_const/_Ry + + wfr = SRWLWfr() + wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions (may be modified by the library!) + + eStep = 0 if(_mesh.ne <= 1) else (_mesh.eFin - _mesh.eStart)/(_mesh.ne - 1) + xStep = 0 if(_mesh.nx <= 1) else (_mesh.xFin - _mesh.xStart)/(_mesh.nx - 1) + yStep = 0 if(_mesh.ny <= 1) else (_mesh.yFin - _mesh.yStart)/(_mesh.ny - 1) + + halfPerX = _mesh.ne + halfPerY = halfPerX*_mesh.nx + ePh = _mesh.eStart + + for ie in range(_mesh.ne): + constRxE = constRx*ePh + constRyE = constRy*ePh + + y = _mesh.yStart - _yc + for iy in range(_mesh.ny): + dPhaseY = constRyE*y*y + + halfPerYiy_p_ie = halfPerY*iy + ie + + x = _mesh.xStart - _xc + for ix in range(_mesh.nx): + phase = dPhaseY + constRxE*x*x + cosPhase = cos(phase) + sinPhase = sin(phase) + + ofstI = halfPerYiy_p_ie + halfPerX*ix + curI = abs(_ar_int[ofstI]) + magn = sqrt(curI) + + ofstE = ofstI*2 + wfr.arEx[ofstE] = magn*cosPhase + wfr.arEy[ofstE] = 0 + ofstE += 1 + wfr.arEx[ofstE] = magn*sinPhase + wfr.arEy[ofstE] = 0 + + x += xStep + y += yStep + ePh += eStep + + #More wavefront parameters + wfr.partBeam = _part_beam + wfr.mesh = deepcopy(_mesh) + wfr.Rx = _Rx #instant wavefront radii + wfr.Ry = _Ry + wfr.dRx = 0.01*_Rx #error of wavefront radii + wfr.dRy = 0.01*_Ry + wfr.xc = _xc #instant transverse coordinates of wavefront instant "source center" + wfr.yc = _yc + wfr.avgPhotEn = _mesh.eStart if(_mesh.ne == 1) else 0.5*(_mesh.eStart + _mesh.eFin) #average photon energy for time-domain simulations + wfr.presCA = 0 #presentation/domain: 0- coordinates, 1- angles + wfr.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + wfr.unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) ? + #wfr.arElecPropMatr = array('d', [0] * 20) #effective 1st order "propagation matrix" for electron beam parameters + #wfr.arMomX = array('d', [0] * 11 * _ne) #statistical moments (of Wigner distribution); to check the exact number of moments required + #wfr.arMomY = array('d', [0] * 11 * _ne) + #wfr.arWfrAuxData = array('d', [0] * 30) #array of auxiliary wavefront data + + return wfr + +#**********************Main Partially-Coherent Emission and Propagaiton simulation function +def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_part_tot, _n_part_avg_proc=1, _n_save_per=100, + _file_path=None, _sr_samp_fact=-1, _opt_bl=None, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, + #_rand_meth=1, _tryToUseMPI=True): + #_rand_meth=1, _tryToUseMPI=True, _w_wr=0.): #OC26032016 (added _w_wr) + #_rand_meth=1, _tryToUseMPI=True, _wr=0.): #OC07092016 (renamed _wr) + #_rand_meth=1, _tryToUseMPI=True, _wr=0., _det=None): #OC06122016 + #_rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None): #OC05012017 + _rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None, _me_approx=0): #OC05042017 """ Calculate Stokes Parameters of Emitted (and Propagated, if beamline is defined) Partially-Coherent SR :param _e_beam: Finite-Emittance e-beam (SRWLPartBeam type) - :param _mag: Magnetic Field container (magFldCnt type) + :param _mag: Magnetic Field container (magFldCnt type) or Coherent Gaussian beam (SRWLGsnBm type) or Point Source (SRWLPtSrc type) :param _mesh: mesh vs photon energy, horizontal and vertical positions (SRWLRadMesh type) on which initial SR should be calculated - :param _sr_meth: SR Electric Field calculation method to be used (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") + :param _sr_meth: SR Electric Field calculation method to be used: 0- "manual", 1- "auto-undulator", 2- "auto-wiggler" :param _sr_rel_prec: relative precision for SR Electric Field calculation (usually 0.01 is OK, the smaller the more accurate) :param _n_part_tot: total number of "macro-electrons" to be used in the calculation :param _n_part_avg_proc: number of "macro-electrons" to be used in calculation at each "slave" before sending Stokes data to "master" (effective if the calculation is run via MPI) @@ -1629,74 +5864,160 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ :param _sr_samp_fact: oversampling factor for calculating of initial wavefront for subsequent propagation (effective if >0) :param _opt_bl: optical beamline (container) to propagate the radiation through (SRWLOptC type) :param _pres_ang: switch specifying presentation of the resulting Stokes parameters: coordinate (0) or angular (1) + :param _char: radiation characteristic to calculate: + 0- Total Intensity, i.e. Flux per Unit Surface Area (s0); + 1- Four Stokes components of Flux per Unit Surface Area; + 2- Mutual Intensity Cut vs X; + 3- Mutual Intensity Cut vs Y; + 4- Mutual Intensity Cuts and Degree of Coherence vs X & Y; + 10- Flux + 20- Electric Field (sum of fields from all macro-electrons, assuming CSR) + 40- Total Intensity, i.e. Flux per Unit Surface Area (s0), Mutual Intensity Cuts and Degree of Coherence vs X & Y; + :param _x0: horizontal center position for mutual intensity calculation + :param _y0: vertical center position for mutual intensity calculation + :param _e_ph_integ: integration over photon energy is required (1) or not (0); if the integration is required, the limits are taken from _mesh + :param _rand_meth: method for generation of pseudo-random numbers for e-beam phase-space integration: + 1- standard pseudo-random number generator + 2- Halton sequences + 3- LPtau sequences (to be implemented) + :param _tryToUseMPI: switch specifying whether MPI should be attempted to be used + :param _wr: initial wavefront radius [m] to assume at wavefront propagation (is taken into account if != 0) + :param _wre: initial wavefront radius error [m] to assume at wavefront propagation (is taken into account if != 0) + :param _det: detector object for post-processing of final intensity (instance of SRWLDet) + :param _me_approx: approximation to be used at multi-electron integration: 0- none (i.e. do standard M-C integration over 5D phase space volume of e-beam), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance """ + doMutual = 0 #OC30052017 + if((_char >= 2) and (_char <= 4)): doMutual = 1 + + if((_det is not None) and (doMutual > 0)): raise Exception("Detector processing is not supported for mutual intensity") #OC30052017 + + import time #DEBUG + #print('_mesh.xStart=', _mesh.xStart, '_mesh.xFin=', _mesh.xFin, '_mesh.yStart=', _mesh.yStart, '_mesh.yFin=', _mesh.yFin) #DEBUG + #print('_sr_samp_fact:', _sr_samp_fact) #DEBUG + #for i in range(len(_opt_bl.arProp)): #DEBUG + # print(i, _opt_bl.arProp[i]) #DEBUG + + #DEBUG + #self.arOpt = [] + #self.arProp = [] + nProc = 1 rank = 1 MPI = None comMPI = None - try: - resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], -1) #MPI module load - MPI = resImpMPI4Py.MPI - comMPI = MPI.COMM_WORLD - rank = comMPI.Get_rank() - nProc = comMPI.Get_size() - except: - print('Calculation will be sequential (non-parallel), because "mpi4py" module can not be loaded') + if(_tryToUseMPI): + try: + ##DEBUG + ##resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], -1) #MPI module load + #resImpMPI4Py = __import__('mpi4py', globals(), locals(), ['MPI'], 0) #MPI module load + ##print('__import__ passed') + #MPI = resImpMPI4Py.MPI - if(nProc <= 1): - _n_part_avg_proc = _n_part_tot + from mpi4py import MPI #OC091014 + + comMPI = MPI.COMM_WORLD + rank = comMPI.Get_rank() + nProc = comMPI.Get_size() + + except: + print('Calculation will be sequential (non-parallel), because "mpi4py" module can not be loaded') + + #print('DEBUG:', MPI) + #print('DEBUG: rank, nProc:', rank, nProc) + + #if(nProc <= 1): #OC050214 + # _n_part_avg_proc = _n_part_tot + + #OC30052017 (commented-out) + #wfr = SRWLWfr() #Wavefronts to be used in each process + #wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + #wfr.mesh.set_from_other(_mesh) + #wfr.partBeam = deepcopy(_e_beam) + + #arPrecParSR = [_sr_meth, _sr_rel_prec, 0, 0, 50000, 0, _sr_samp_fact] #to add npTraj, useTermin ([4], [5]) terms as input parameters + arPrecParSR = [_sr_meth, _sr_rel_prec, 0, 0, 50000, 1, _sr_samp_fact] #to add npTraj, useTermin ([4], [5]) terms as input parameters + + meshRes = SRWLRadMesh(_mesh.eStart, _mesh.eFin, _mesh.ne, _mesh.xStart, _mesh.xFin, _mesh.nx, _mesh.yStart, _mesh.yFin, _mesh.ny, _mesh.zStart) #OC30052017 (uncommented) #to ensure correct final mesh if _opt_bl is None + #meshRes = SRWLRadMesh(_mesh.eStart, _mesh.eFin, _mesh.ne, _mesh.xStart, _mesh.xFin, _mesh.nx, _mesh.yStart, _mesh.yFin, _mesh.ny, _mesh.zStart) if(_det is None) else _det.get_mesh() #OC06122016 + #Note: the case ((_det is not None) and (doMutual > 0)) is not supported + + file_path1 = copy(_file_path) #OC30052017 + file_path2 = None + file_path_deg_coh1 = None #07052018 + file_path_deg_coh2 = None + meshRes2 = None #OC30052017 + #if(_char == 4): #Mutual Intensity Cuts vs X & Y are required + if((_char == 4) or (_char == 40)): #OC02052018 #Mutual Intensity Cuts vs X & Y are required + #meshRes2 = copy(meshRes) + if(_char == 4): meshRes2 = copy(meshRes) #OC02052018 + file_path1 += '.1' + file_path2 = copy(_file_path) + '.2' + file_path_deg_coh1 = copy(_file_path) + '.dc.1' + file_path_deg_coh2 = copy(_file_path) + '.dc.2' wfr = SRWLWfr() #Wavefronts to be used in each process - wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions - wfr.mesh.set_from_other(_mesh) - wfr.partBeam = deepcopy(_e_beam) - arPrecParSR = [_sr_meth, _sr_rel_prec, 0, 0, 50000, 0, _sr_samp_fact] - meshRes = SRWLRadMesh() + wfr2 = None #OC30052017 + if((_opt_bl is None) and (doMutual > 0)): #OC30052017 + if(_char == 2): #Cut vs X + meshRes.ny = 1 + meshRes.yStart = _y0 + meshRes.yFin = _y0 + elif(_char == 3): #Cut vs Y + meshRes.nx = 1 + meshRes.xStart = _x0 + meshRes.xFin = _x0 + elif(_char == 4): #Cuts of Mutual Intensity vs X & Y + meshRes.ny = 1 + meshRes.yStart = _y0 + meshRes.yFin = _y0 + meshRes2.nx = 1 + meshRes2.xStart = _x0 + meshRes2.xFin = _x0 + wfr2 = SRWLWfr() - resStokes = None - workStokes = None - iAvgProc = 0 - iSave = 0 - - if(((rank == 0) or (nProc == 1)) and (_opt_bl != None)): #calculate once the central wavefront in the master process (this has to be done only if propagation is required) - srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecParSR) - #print('DEBUG MESSAGE: Central Wavefront calculated') - srwl.PropagElecField(wfr, _opt_bl) - #print('DEBUG MESSAGE: Central Wavefront propagated') - if(_pres_ang > 0): - srwl.SetRepresElecField(wfr, 'a') - - meshRes.set_from_other(wfr.mesh) + #OC30052017 + wfr.allocate(meshRes.ne, meshRes.nx, meshRes.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr.mesh.set_from_other(meshRes) + wfr.partBeam = deepcopy(_e_beam) + if(wfr2 is not None): + wfr2.allocate(meshRes2.ne, meshRes2.nx, meshRes2.ny) #Numbers of points vs Photon Energy, Horizontal and Vertical Positions + wfr2.mesh.set_from_other(meshRes2) + wfr2.partBeam = deepcopy(_e_beam) - if(nProc > 1): #send resulting mesh to all workers - #comMPI.send(wfr.mesh, dest=) - arMesh = array('f', [meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny]) - #comMPI.Bcast([arMesh, MPI.FLOAT], root=MPI.ROOT) - #comMPI.Bcast([arMesh, MPI.FLOAT]) + if(_det is not None): meshRes = _det.get_mesh() #OC06122016 - for iRank in range(nProc - 1): - dst = iRank + 1 - comMPI.Send([arMesh, MPI.FLOAT], dest=dst) - #print('DEBUG MESSAGE: Mesh of Propagated central wavefront broadcasted') + ePhIntegMult = 1 + if(_e_ph_integ == 1): #Integrate over Photon Energy + eAvg = 0.5*(_mesh.eStart + _mesh.eFin) + ePhIntegMult = 1000*(_mesh.eFin - _mesh.eStart)/eAvg #To obtain photon energy integrated Intensity in [ph/s/mm^2] assuming monochromatic Spectral Intensity in [ph/s/.1%bw/mm^2] + wfr.mesh.eStart = eAvg + wfr.mesh.eFin = eAvg + wfr.mesh.ne = 1 + if(wfr2 is not None): + wfr2.mesh.eStart = eAvg #OC30052017 + wfr2.mesh.eFin = eAvg + wfr2.mesh.ne = 1 + meshRes.eStart = eAvg #to check compatibility with _mesh_res is not None + meshRes.eFin = eAvg + meshRes.ne = 1 + if(meshRes2 is not None): #OC30052017 + meshRes2.eStart = eAvg #to check compatibility with _mesh_res is not None + meshRes2.eFin = eAvg + meshRes2.ne = 1 - resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny) - wfr.calc_stokes(resStokes) - workStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny) + calcSpecFluxSrc = False + if((_char == 10) and (_mesh.nx == 1) and (_mesh.ny == 1)): + calcSpecFluxSrc = True + ePhIntegMult *= 1.e+06*(_mesh.xFin - _mesh.xStart)*(_mesh.yFin - _mesh.yStart) #to obtain Flux from Intensity (Flux/mm^2) - #print('DEBUG MESSAGE: parameters of Propagated central wavefront calculated') - #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1) - #sys.exit(0) - iAvgProc += 1 - iSave += 1 - elecX0 = _e_beam.partStatMom1.x elecXp0 = _e_beam.partStatMom1.xp elecY0 = _e_beam.partStatMom1.y elecYp0 = _e_beam.partStatMom1.yp elecGamma0 = _e_beam.partStatMom1.gamma - elecE0 = elecGamma0*(0.51099890221e-03) + elecE0 = elecGamma0*(0.51099890221e-03) #Assuming electrons elecSigXe2 = _e_beam.arStatMom2[0] #<(x-x0)^2> elecMXXp = _e_beam.arStatMom2[1] #<(x-x0)*(xp-xp0)> @@ -1707,6 +6028,7 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ elecRelEnSpr = sqrt(_e_beam.arStatMom2[10]) #<(E-E0)^2>/E0^2 elecAbsEnSpr = elecE0*elecRelEnSpr #print('DEBUG MESSAGE: elecAbsEnSpr=', elecAbsEnSpr) + #Consider taking into account other 2nd order moments? multX = 0.5/(elecSigXe2*elecSigXpe2 - elecMXXp*elecMXXp) BX = elecSigXe2*multX @@ -1721,16 +6043,272 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ SigPY = 1/sqrt(2*GY) SigQY = sqrt(GY/(2*(BY*GY - AY*AY))) - nPartPerProc = int(_n_part_tot/nProc) + #_sr_rel_prec = int(_sr_rel_prec) + + _n_part_tot = int(_n_part_tot) + _n_part_avg_proc = int(_n_part_avg_proc) + if(_n_part_avg_proc <= 0): _n_part_avg_proc = 1 + _n_save_per = int(_n_save_per) + + nPartPerProc = _n_part_tot + nSentPerProc = 0 + + if(nProc <= 1): + _n_part_avg_proc = _n_part_tot + else: #OC050214: adjustment of all numbers of points, to make sure that sending and receiving are consistent + + nPartPerProc = int(round(_n_part_tot/(nProc - 1))) + nSentPerProc = int(round(nPartPerProc/_n_part_avg_proc)) #Number of sending acts made by each worker process + + if(nSentPerProc <= 0): #OC160116 + nSentPerProc = 1 + _n_part_avg_proc = nPartPerProc + + nPartPerProc = _n_part_avg_proc*nSentPerProc #Number of electrons treated by each worker process + + #print('DEBUG MESSAGE: rank:', rank,': nPartPerProc=', nPartPerProc, 'nSentPerProc=', nSentPerProc, '_n_part_avg_proc=', _n_part_avg_proc) + + log_path, total_num_of_particles = srwl_uti_save_stat_wfr_emit_prop_multi_e_init(rank, nProc, nPartPerProc, nSentPerProc, _n_part_avg_proc) #MR20012017 + + useGsnBmSrc = False + usePtSrc = False #OC16102017 + if(isinstance(_mag, SRWLGsnBm)): + useGsnBmSrc = True + arPrecParSR = [_sr_samp_fact] + _mag = deepcopy(_mag) + _mag.x = elecX0 + _mag.xp = elecXp0 + _mag.y = elecY0 + _mag.yp = elecYp0 + #print('Gaussian Beam') + #sys.exit() + elif(isinstance(_mag, SRWLPtSrc)): + usePtSrc = True #OC16102017 + arPrecParSR = [_sr_samp_fact] + _mag = deepcopy(_mag) + _mag.x = elecX0 + _mag.xp = 0 + _mag.y = elecY0 + _mag.yp = 0 + + resStokes = None + workStokes = None + resStokes2 = None #OC30052017 + workStokes2 = None + arAuxResSt12 = None #OC31052017 + arAuxWorkSt12 = None #OC31052017 + + resStokes3 = None #OC03052018 + workStokes3 = None + arAuxResSt123 = None #OC03052018 + arAuxWorkSt123 = None #OC03052018 + + iAvgProc = 0 + iSave = 0 + + #doMutual = 0 + #if((_char >= 2) and (_char <= 4)): doMutual = 1 + + #depTypeME_Approx = 3 #vs x&y (horizontal and vertical positions or angles); to be used only at _me_approx > 0 + #OC15092017 + depTypeInt = 3 #vs x&y (horizontal and vertical positions or angles); to be used only at _me_approx > 0 + #phEnME_Approx = _mesh.eStart + phEnInt = _mesh.eStart #OC15092017 + #if(_me_approx == 1): #OC15092017 + #if((_mesh.nx <= 1) or (_mesh.ny <= 1)): + if((_me_approx == 1) and ((_mesh.nx <= 1) or (_mesh.ny <= 1))): #OC01102017 + raise Exception("This calculation method requires more than one observation point in the horizontal and vertical directions") + + if(_mesh.ne > 1): + #OC15092017 + depTypeInt = 6 #vs e&x&y (photon energy or time, horizontal and vertical positions or angles) + phEnInt = 0.5*(_mesh.eStart + _mesh.eFin) + #depTypeME_Approx = 6 #vs e&x&y (photon energy or time, horizontal and vertical positions or angles) + #phEnME_Approx = 0.5*(_mesh.eStart + _mesh.eFin) + + resEntityName = 'Intensity' #OC26042016 + resEntityUnits = 'ph/s/.1%bw/mm^2' + resLabelsToSave = ['Photon Energy', 'Horizontal Position', 'Vertical Position', resEntityName] #OC26042016 + resUnitsToSave = ['eV', 'm', 'm', resEntityUnits] #OC26042016 + + if(_pres_ang > 0): #OC20112017 + resEntityName = 'Ang. Intensity Distr.' + resEntityUnits = 'ph/s/.1%bw/mrad^2' + resLabelsToSave = ['Photon Energy', 'Horizontal Angle', 'Vertical Angle', resEntityName] + resUnitsToSave = ['eV', 'rad', 'rad', resEntityUnits] + + if(calcSpecFluxSrc == True): + resEntityName = 'Flux' + resEntityUnits = 'ph/s/.1%bw' + resLabelsToSave[3] = resEntityName #OC27032018 + resUnitsToSave[3] = resEntityUnits #OC27032018 + + #resLabelsToSaveMutualHorCut = [resLabelsToSave[0], resLabelsToSave[1], 'Conj. ' + resLabelsToSave[1], 'Mutual ' + resLabelsToSave[3]] #OC03052018 + #resLabelsToSaveMutualVerCut = [resLabelsToSave[0], resLabelsToSave[2], 'Conj. ' + resLabelsToSave[2], 'Mutual ' + resLabelsToSave[3]] + + #if(((rank == 0) or (nProc == 1)) and (_opt_bl != None)): #calculate once the central wavefront in the master process (this has to be done only if propagation is required) + if(((rank == 0) or (nProc == 1)) and (_det is None)): #12/01/2017 + + if(useGsnBmSrc): + srwl.CalcElecFieldGaussian(wfr, _mag, arPrecParSR) + if(wfr2 is not None): srwl.CalcElecFieldGaussian(wfr2, _mag, arPrecParSR) #OC30052017 + #print('DEBUG: Commented-out: CalcElecFieldGaussian') + elif(usePtSrc): #OC16102017 + srwl.CalcElecFieldPointSrc(wfr, _mag, arPrecParSR) + if(wfr2 is not None): srwl.CalcElecFieldPointSrc(wfr2, _mag, arPrecParSR) + else: + + #print('Single-electron SR calculation ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + #print('DEBUG: wfr.mesh:', wfr.mesh) + srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecParSR) + + if(wfr2 is not None): + #print('DEBUG: wfr2.mesh:', wfr2.mesh) + srwl.CalcElecFieldSR(wfr2, 0, _mag, arPrecParSR) #OC30052017 + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #print('DEBUG MESSAGE: CalcElecFieldSR called (rank:', rank,')') + + #print('DEBUG MESSAGE: Central Wavefront calculated') + + #print('Wavefront propagation calculation ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #if(_w_wr != 0.): #OC26032016 + if(_wr != 0.): #OC07092016 + wfr.Rx = _wr + wfr.Ry = _wr + if(wfr2 is not None): #OC30052017 + wfr2.Rx = _wr + wfr2.Ry = _wr + + if(_wre > 0.): #OC05012017 + wfr.dRx = _wre + wfr.dRy = _wre + if(wfr2 is not None): #OC30052017 + wfr2.dRx = _wre + wfr2.dRy = _wre + + if(_opt_bl is not None): #OC16012017 + srwl.PropagElecField(wfr, _opt_bl) + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #meshRes.set_from_other(wfr.mesh) #DEBUG + #resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) #DEBUG + #wfr.calc_stokes(resStokes) #DEBUG + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _mutual = doMutual) #DEBUG + + #print('DEBUG: Commented-out: PropagElecField') + #print('DEBUG MESSAGE: Central Wavefront propagated') + if(_pres_ang > 0): + wfr.unitElFldAng = 1 #OC20112017 (to ensure result in [ph/s/.1%bw/mrad^2]) + srwl.SetRepresElecField(wfr, 'a') + if(wfr2 is not None): + wfr2.unitElFldAng = 1 #OC20112017 + srwl.SetRepresElecField(wfr2, 'a') #OC30052017 + #print('DEBUG: Commented-out: SetRepresElecField') + + #meshRes.set_from_other(wfr.mesh) + #if(_det is None): meshRes.set_from_other(wfr.mesh) #OC06122016 + #else: meshRes = _det.get_mesh() #?? + + meshRes.set_from_other(wfr.mesh) #OC12012016 + + #if(wfr2 is not None): meshRes2.set_from_other(wfr2.mesh) #OC30052017 + + if(doMutual > 0): + if(_char == 2): #Cut vs X + meshRes.ny = 1 + meshRes.yStart = _y0 + meshRes.yFin = _y0 + elif(_char == 3): #Cut vs Y + meshRes.nx = 1 + meshRes.xStart = _x0 + meshRes.xFin = _x0 + elif(_char == 4): #Cuts of Mutual Intensity vs X & Y + meshRes.ny = 1 + meshRes.yStart = _y0 + meshRes.yFin = _y0 + if(wfr2 is None): meshRes2.set_from_other(wfr.mesh) #OC31052017 + else: meshRes2.set_from_other(wfr2.mesh) #OC31052017 + meshRes2.nx = 1 + meshRes2.xStart = _x0 + meshRes2.xFin = _x0 + + if(nProc > 1): #send resulting mesh to all workers + #comMPI.send(wfr.mesh, dest=) + arMesh = array('f', [meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny]) + + #arMesh2 = None #OC30052017 + if(_char == 4): #Cuts of Mutual Intensity vs X & Y + arMesh2 = array('f', [meshRes2.eStart, meshRes2.eFin, meshRes2.ne, meshRes2.xStart, meshRes2.xFin, meshRes2.nx, meshRes2.yStart, meshRes2.yFin, meshRes2.ny]) + for ii in range(len(arMesh2)): #OC31052017 + arMesh.append(arMesh2[ii]) + + #comMPI.Bcast([arMesh, MPI.FLOAT], root=MPI.ROOT) + #comMPI.Bcast([arMesh, MPI.FLOAT]) + + #print('DEBUG MESSAGE: Rank0 is about to broadcast mesh of Propagated central wavefront') + for iRank in range(nProc - 1): + dst = iRank + 1 + #print("msg %d: sending data from %d to %d" % (iRank, rank, dst)) #an he + comMPI.Send([arMesh, MPI.FLOAT], dest=dst) + + #OC30052017 + #if(_char == 4): #Cuts of Mutual Intensity vs X & Y + # comMPI.Send([arMesh2, MPI.FLOAT], dest=dst) + + #print('DEBUG MESSAGE: Mesh of Propagated central wavefront broadcasted') + + #DEBUG + #print('meshRes: ne=', meshRes.ne, 'eStart=', meshRes.eStart, 'eFin=', meshRes.eFin) + #print('meshRes: nx=', meshRes.nx, 'xStart=', meshRes.xStart, 'xFin=', meshRes.xFin) + #print('meshRes: ny=', meshRes.ny, 'yStart=', meshRes.yStart, 'yFin=', meshRes.yFin) + #END DEBUG + + resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) + #wfr.calc_stokes(resStokes) #OC190414: don't take into account the first "central" beam! + #workStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) + #OC06042017 (commented-out workStokes = ...) + + if(_char == 4): #OC31052017 #Cuts of Mutual Intensity vs X & Y + resStokes2 = SRWLStokes(1, 'f', meshRes2.eStart, meshRes2.eFin, meshRes2.ne, meshRes2.xStart, meshRes2.xFin, meshRes2.nx, meshRes2.yStart, meshRes2.yFin, meshRes2.ny, doMutual) + lenArSt12 = len(resStokes.arS) + len(resStokes2.arS) + arAuxResSt12 = array('f', [0]*lenArSt12) + + if(_char == 40): #OC03052018 #Intensity and Cuts of Mutual Intensity vs X & Y + resStokes2 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, _y0, _y0, 1, _mutual=1) + resStokes3 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, _x0, _x0, 1, meshRes.yStart, meshRes.yFin, meshRes.ny, _mutual=1) + lenArSt123 = len(resStokes.arS) + len(resStokes2.arS) + len(resStokes3.arS) + arAuxResSt123 = array('f', [0]*lenArSt123) + + #iAvgProc += 1 #OC190414 (commented-out) + #iSave += 1 + + #slaves = [] #an he #print('DEBUG MESSAGE: rank=', rank) + numComp = 1 + if(_char == 20): numComp = 4 #OC16012017 + + if(_opt_bl is None): arPrecParSR[6] = 0 #Ensure non-automatic choice of numbers of points if there is no beamline + if((rank > 0) or (nProc == 1)): - if((nProc > 1) and (_opt_bl != None)): #receive mesh for the resulting wavefront from the master - arMesh = array('f', [0]*9) + #if((nProc > 1) and (_opt_bl != None)): #receive mesh for the resulting wavefront from the master + #if((nProc > 1) and (_opt_bl is not None) and (_det is None)): #OC12012017 #receive mesh for the resulting wavefront from the master + if((nProc > 1) and (_det is None)): #OC16012017 #receive mesh for the resulting wavefront from the master + #arMesh = array('f', [0]*9) + nNumToRecv = 9 + if(_char == 4): nNumToRecv = 18 #OC31052017 #Cuts of Mutual Intensity vs X & Y + arMesh = array('f', [0]*nNumToRecv) + + #_stat = MPI.Status() #an he #comMPI.Recv([arMesh, MPI.FLOAT], source=0) comMPI.Recv([arMesh, MPI.FLOAT], source=MPI.ANY_SOURCE) #comMPI.Bcast([arMesh, MPI.FLOAT], root=0) + #print("received mesh %d -> %d" % (_stat.Get_source(), rank)) meshRes.eStart = arMesh[0] meshRes.eFin = arMesh[1] meshRes.ne = int(arMesh[2]) @@ -1740,84 +6318,559 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ meshRes.yStart = arMesh[6] meshRes.yFin = arMesh[7] meshRes.ny = int(arMesh[8]) + + #arMesh2 = None #OC30052017 + if(_char == 4): #Cuts of Mutual Intensity vs X & Y + #arMesh2 = array('f', [0]*9) + #_stat = MPI.Status() #an he + #comMPI.Recv([arMesh2, MPI.FLOAT], source=MPI.ANY_SOURCE) + #comMPI.Bcast([arMesh, MPI.FLOAT], root=0) + #print("received mesh %d -> %d" % (_stat.Get_source(), rank)) + meshRes2.eStart = arMesh[9] #OC31052017 + meshRes2.eFin = arMesh[10] + meshRes2.ne = int(arMesh[11]) + meshRes2.xStart = arMesh[12] + meshRes2.xFin = arMesh[13] + meshRes2.nx = int(arMesh[14]) + meshRes2.yStart = arMesh[15] + meshRes2.yFin = arMesh[16] + meshRes2.ny = int(arMesh[17]) + #sys.exit(0) nRadPt = meshRes.ne*meshRes.nx*meshRes.ny + if(doMutual > 0): nRadPt *= nRadPt nStPt = nRadPt*4 - randAr = array('d', [0]*5) #to expend to 6D eventually - random.seed(rank) + nRadPt2 = None #OC30052017 + nStPt2 = None + if(_char == 4): #Cuts of Mutual Intensity vs X & Y + nRadPt2 = meshRes2.ne*meshRes2.nx*meshRes2.ny + if(doMutual > 0): nRadPt2 *= nRadPt2 #OC03052018 + nStPt2 = nRadPt2*4 + + nRadPt3 = None #OC03052018 + nStPt3 = None + if(_char == 40): #Intensity and Cuts of Mutual Intensity vs X & Y + nRadPt2 = meshRes.ne*meshRes.nx + nRadPt2 *= nRadPt2 + nStPt2 = nRadPt2*4 + nRadPt3 = meshRes.ne*meshRes.ny + nRadPt3 *= nRadPt3 + nStPt3 = nRadPt3*4 + + randAr = array('d', [0]*6) #for random Gaussian numbers + + #random.seed(rank) + random.seed(rank*123) + newSeed = random.randint(0, 1000000) + random.seed(newSeed) + + iAuxSendCount = 0 #for debug for i in range(nPartPerProc): #loop over macro-electrons - for ir in range(5): #to expend to 6D eventually - randAr[ir] = random.gauss(0, 1) - #DEBUG - #if(i == 0): - # randAr = array('d', [0,0,0,2,0]) - #if(i == 1): - # randAr = array('d', [0,0,0,-2,0]) - #END DEBUG + if(_me_approx == 0): #OC05042017 #General method + + if(_rand_meth == 1): + for ir in range(5): #to expend to 6D eventually + randAr[ir] = random.gauss(0, 1) + elif(_rand_meth == 2): + if(nProc > 1): + iArg = i*(nProc - 1) + rank + a1 = srwl_uti_math_seq_halton(iArg, 2) + a2 = srwl_uti_math_seq_halton(iArg, 3) + a3 = srwl_uti_math_seq_halton(iArg, 5) + a4 = srwl_uti_math_seq_halton(iArg, 7) + a5 = srwl_uti_math_seq_halton(iArg, 11) #? + elif(nProc == 1): + i_p_1 = i + 1 + a1 = srwl_uti_math_seq_halton(i_p_1, 2) + a2 = srwl_uti_math_seq_halton(i_p_1, 3) + a3 = srwl_uti_math_seq_halton(i_p_1, 5) + a4 = srwl_uti_math_seq_halton(i_p_1, 7) + a5 = srwl_uti_math_seq_halton(i_p_1, 11) #? + twoPi = 2*pi + twoPi_a2 = twoPi*a2 + twoPi_a4 = twoPi*a4 + m2_log_a1 = -2.0*log(a1) + m2_log_a3 = -2.0*log(a3) + randAr[0] = sqrt(m2_log_a1)*cos(twoPi_a2) + randAr[1] = sqrt(m2_log_a1)*sin(twoPi_a2) + randAr[2] = sqrt(m2_log_a3)*cos(twoPi_a4) + randAr[3] = sqrt(m2_log_a3)*sin(twoPi_a4) + randAr[4] = sqrt(m2_log_a1)*cos(twoPi*a3) #or just random.gauss(0,1) depends on cases #why not using a5? + randAr[5] = a5 + elif(_rand_meth == 3): + #to program LPtau sequences here + continue + + #DEBUG + #if(i == 0): + # randAr = array('d', [0,0,0,2,0]) + #if(i == 1): + # randAr = array('d', [0,0,0,-2,0]) + #END DEBUG + + auxPXp = SigQX*randAr[0] + auxPX = SigPX*randAr[1] + AX*auxPXp/GX + wfr.partBeam.partStatMom1.x = elecX0 + auxPX + wfr.partBeam.partStatMom1.xp = elecXp0 + auxPXp + auxPYp = SigQY*randAr[2] + auxPY = SigPY*randAr[3] + AY*auxPYp/GY + wfr.partBeam.partStatMom1.y = elecY0 + auxPY + wfr.partBeam.partStatMom1.yp = elecYp0 + auxPYp + #wfr.partBeam.partStatMom1.gamma = (elecEn0 + elecAbsEnSpr*randAr[4])/0.51099890221e-03 #Relative Energy + #wfr.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecAbsEnSpr*randAr[4]/elecE0) + wfr.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecRelEnSpr*randAr[4]) #OC28122016 + + if(wfr2 is not None): #OC30052017 + wfr2.partBeam.partStatMom1.x = elecX0 + auxPX + wfr2.partBeam.partStatMom1.xp = elecXp0 + auxPXp + wfr2.partBeam.partStatMom1.y = elecY0 + auxPY + wfr2.partBeam.partStatMom1.yp = elecYp0 + auxPYp + wfr2.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecRelEnSpr*randAr[4]) #OC28122016 + + #Consider taking into account other 2nd order moments? + + elif(_me_approx == 1): #OC05042017 #Numerical integration only over electron energy + + if(_rand_meth == 1): + randAr[0] = random.gauss(0, 1) + elif(_rand_meth == 2): + if(nProc > 1): + iArg = i*(nProc - 1) + rank + a1 = srwl_uti_math_seq_halton(iArg, 2) + a2 = srwl_uti_math_seq_halton(iArg, 3) + #a3 = srwl_uti_math_seq_halton(iArg, 5) + #a4 = srwl_uti_math_seq_halton(iArg, 7) + #a5 = srwl_uti_math_seq_halton(iArg, 11) #? + elif(nProc == 1): + i_p_1 = i + 1 + a1 = srwl_uti_math_seq_halton(i_p_1, 2) + a2 = srwl_uti_math_seq_halton(i_p_1, 3) + #a3 = srwl_uti_math_seq_halton(i_p_1, 5) + #a4 = srwl_uti_math_seq_halton(i_p_1, 7) + #a5 = srwl_uti_math_seq_halton(i_p_1, 11) #? + twoPi = 2*pi + twoPi_a2 = twoPi*a2 + #twoPi_a4 = twoPi*a4 + m2_log_a1 = -2.0*log(a1) + #m2_log_a3 = -2.0*log(a3) + randAr[0] = sqrt(m2_log_a1)*cos(twoPi_a2) + #randAr[1] = sqrt(m2_log_a1)*sin(twoPi_a2) + #randAr[2] = sqrt(m2_log_a3)*cos(twoPi_a4) + #randAr[3] = sqrt(m2_log_a3)*sin(twoPi_a4) + #randAr[4] = sqrt(m2_log_a1)*cos(twoPi*a3) #or just random.gauss(0,1) depends on cases #why not using a5? + #randAr[5] = a5 + elif(_rand_meth == 3): + #to program LPtau sequences here + continue + + wfr.partBeam.partStatMom1.x = elecX0 + wfr.partBeam.partStatMom1.xp = elecXp0 + wfr.partBeam.partStatMom1.y = elecY0 + wfr.partBeam.partStatMom1.yp = elecYp0 + wfr.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecRelEnSpr*randAr[0]) #OC05042017 + if(wfr2 is not None): #OC30052017 + wfr2.partBeam.partStatMom1.x = elecX0 + wfr2.partBeam.partStatMom1.xp = elecXp0 + wfr2.partBeam.partStatMom1.y = elecY0 + wfr2.partBeam.partStatMom1.yp = elecYp0 + wfr2.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecRelEnSpr*randAr[0]) + + #OC06042017 (added for _me_approx == 1 and possibly other future methods) + wfr.partBeam.arStatMom2[0] = elecSigXe2 #<(x-x0)^2> + wfr.partBeam.arStatMom2[1] = elecMXXp #<(x-x0)*(xp-xp0)> + wfr.partBeam.arStatMom2[2] = elecSigXpe2 #<(xp-xp0)^2> + wfr.partBeam.arStatMom2[3] = elecSigYe2 #<(y-y0)^2> + wfr.partBeam.arStatMom2[4] = elecMYYp #<(y-y0)*(yp-yp0)> + wfr.partBeam.arStatMom2[5] = elecSigYpe2 #<(yp-yp0)^2> + wfr.partBeam.arStatMom2[10] = elecRelEnSpr*elecRelEnSpr #<(E-E0)^2>/E0^2 + if(wfr2 is not None): #OC30052017 + wfr2.partBeam.arStatMom2[0] = elecSigXe2 #<(x-x0)^2> + wfr2.partBeam.arStatMom2[1] = elecMXXp #<(x-x0)*(xp-xp0)> + wfr2.partBeam.arStatMom2[2] = elecSigXpe2 #<(xp-xp0)^2> + wfr2.partBeam.arStatMom2[3] = elecSigYe2 #<(y-y0)^2> + wfr2.partBeam.arStatMom2[4] = elecMYYp #<(y-y0)*(yp-yp0)> + wfr2.partBeam.arStatMom2[5] = elecSigYpe2 #<(yp-yp0)^2> + wfr2.partBeam.arStatMom2[10] = elecRelEnSpr*elecRelEnSpr #<(E-E0)^2>/E0^2 - auxPXp = SigQX*randAr[0] - auxPX = SigPX*randAr[1] + AX*auxPXp/GX - wfr.partBeam.partStatMom1.x = elecX0 + auxPX - wfr.partBeam.partStatMom1.xp = elecXp0 + auxPXp - auxPYp = SigQY*randAr[2] - auxPY = SigPY*randAr[3] + AY*auxPYp/GY - wfr.partBeam.partStatMom1.y = elecY0 + auxPY - wfr.partBeam.partStatMom1.yp = elecYp0 + auxPYp - #wfr.partBeam.partStatMom1.gamma = (elecEn0 + elecAbsEnSpr*randAr[4])/0.51099890221e-03 #Relative Energy - wfr.partBeam.partStatMom1.gamma = elecGamma0*(1 + elecAbsEnSpr*randAr[4]/elecE0) + #Consider taking into account other 2nd order moments? #reset mesh, because it may be modified by CalcElecFieldSR and PropagElecField - wfr.mesh.set_from_other(_mesh) + #print('Numbers of points (before re-setting): nx=', wfr.mesh.nx, ' ny=', wfr.mesh.ny) #DEBUG + curWfrMesh = wfr.mesh #OC02042016 + newWfrMesh = _mesh if(_opt_bl is not None) else meshRes #OC16012017 + + #if((curWfrMesh.ne != _mesh.ne) or (curWfrMesh.nx != _mesh.nx) or (curWfrMesh.ny != _mesh.ny)): + # wfr.allocate(_mesh.ne, _mesh.nx, _mesh.ny) + if((curWfrMesh.ne != newWfrMesh.ne) or (curWfrMesh.nx != newWfrMesh.nx) or (curWfrMesh.ny != newWfrMesh.ny)): #OC16012017 + wfr.allocate(newWfrMesh.ne, newWfrMesh.nx, newWfrMesh.ny) + + if(_opt_bl is None): wfr.mesh.set_from_other(meshRes) #OC16012017 + else: wfr.mesh.set_from_other(_mesh) + + if(wfr2 is not None): #OC30052017 + curWfrMesh2 = wfr2.mesh + newWfrMesh2 = _mesh if(_opt_bl is not None) else meshRes2 + + if((curWfrMesh2.ne != newWfrMesh2.ne) or (curWfrMesh2.nx != newWfrMesh2.nx) or (curWfrMesh2.ny != newWfrMesh2.ny)): + wfr2.allocate(newWfrMesh2.ne, newWfrMesh2.nx, newWfrMesh2.ny) + + if(_opt_bl is None): wfr2.mesh.set_from_other(meshRes2) + else: wfr2.mesh.set_from_other(_mesh) + + if(_e_ph_integ == 1): + if(_rand_meth == 1): + ePh = random.uniform(_mesh.eStart, _mesh.eFin) + else: + ePh = _mesh.eStart + (_mesh.eFin - _mesh.eStart)*randAr[5] + + wfr.mesh.eStart = ePh + wfr.mesh.eFin = ePh + wfr.mesh.ne = 1 + if(wfr2 is not None): + wfr2.mesh.eStart = ePh + wfr2.mesh.eFin = ePh + wfr2.mesh.ne = 1 + wfr.presCA = 0 #presentation/domain: 0- coordinates, 1- angles wfr.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time + if(wfr2 is not None): + wfr2.presCA = 0 #presentation/domain: 0- coordinates, 1- angles + wfr2.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time if(nProc == 1): - print('i=', i, 'Electron Coord.: x=', wfr.partBeam.partStatMom1.x, 'x\'=', wfr.partBeam.partStatMom1.xp, 'y=', wfr.partBeam.partStatMom1.y, 'y\'=', wfr.partBeam.partStatMom1.yp, 'E=', wfr.partBeam.partStatMom1.gamma*0.51099890221e-03) + if(useGsnBmSrc): print('i=', i, 'Gaussian Beam Coord.: x=', wfr.partBeam.partStatMom1.x, 'x\'=', wfr.partBeam.partStatMom1.xp, 'y=', wfr.partBeam.partStatMom1.y, 'y\'=', wfr.partBeam.partStatMom1.yp) + elif(usePtSrc): print('i=', i, 'Point Source Coord.: x=', wfr.partBeam.partStatMom1.x, 'y=', wfr.partBeam.partStatMom1.y) + else: print('i=', i, 'Electron Coord.: x=', wfr.partBeam.partStatMom1.x, 'x\'=', wfr.partBeam.partStatMom1.xp, 'y=', wfr.partBeam.partStatMom1.y, 'y\'=', wfr.partBeam.partStatMom1.yp, 'E=', wfr.partBeam.partStatMom1.gamma*0.51099890221e-03) + + if(_e_ph_integ == 1): print('Eph=', wfr.mesh.eStart) + + if(calcSpecFluxSrc): #consider taking into account _rand_meth != 1 here + xObs = random.uniform(_mesh.xStart, _mesh.xFin) + wfr.mesh.xStart = xObs + wfr.mesh.xFin = xObs + yObs = random.uniform(_mesh.yStart, _mesh.yFin) + wfr.mesh.yStart = yObs + wfr.mesh.yFin = yObs + #print('xObs=', xObs, 'yObs=', yObs) try: - srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecParSR) #calculate Electric Field emitted by current electron + if(useGsnBmSrc): + _mag.x = wfr.partBeam.partStatMom1.x + _mag.xp = wfr.partBeam.partStatMom1.xp + _mag.y = wfr.partBeam.partStatMom1.y + _mag.yp = wfr.partBeam.partStatMom1.yp + srwl.CalcElecFieldGaussian(wfr, _mag, arPrecParSR) + if(wfr2 is not None): srwl.CalcElecFieldGaussian(wfr2, _mag, arPrecParSR) #OC30052017 + #print('DEBUG: Commented-out: CalcElecFieldGaussian') + #print('Gaussian wavefront calc. done') + elif(usePtSrc): + _mag.x = wfr.partBeam.partStatMom1.x + _mag.xp = 0 + _mag.y = wfr.partBeam.partStatMom1.y + _mag.yp = 0 + srwl.CalcElecFieldPointSrc(wfr, _mag, arPrecParSR) + if(wfr2 is not None): srwl.CalcElecFieldPointSrc(wfr2, _mag, arPrecParSR) #OC30052017 + else: + + #print('Single-electron SR calculatiton ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + #print('arPrecParSR[6]=', arPrecParSR[6]) + + #DEBUG + #print('Numbers of points (after re-setting):') #DEBUG + #print('ne=', wfr.mesh.ne, 'eStart=', wfr.mesh.eStart, 'eFin=', wfr.mesh.eFin) + #print('nx=', wfr.mesh.nx, 'xStart=', wfr.mesh.xStart, 'xFin=', wfr.mesh.xFin) + #print('ny=', wfr.mesh.ny, 'yStart=', wfr.mesh.yStart, 'yFin=', wfr.mesh.yFin) + #print('zStart=', wfr.mesh.zStart) + #END DEBUG + + #DEBUG + #if(i == 48): + # print('Eel=', wfr.partBeam.partStatMom1.get_E(), ' GeV') + # print('xe=', wfr.partBeam.partStatMom1.x, ' xpe=', wfr.partBeam.partStatMom1.xp, ' ye=', wfr.partBeam.partStatMom1.y, ' ype=', wfr.partBeam.partStatMom1.yp) + # print('nx=', wfr.mesh.nx, ' xStart=', wfr.mesh.xStart, ' xFin=', wfr.mesh.xFin) + # print('ny=', wfr.mesh.ny, ' yStart=', wfr.mesh.yStart, ' yFin=', wfr.mesh.yFin) + #END DEBUG + + srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecParSR) #calculate Electric Field emitted by current electron + if(wfr2 is not None): srwl.CalcElecFieldSR(wfr2, 0, _mag, arPrecParSR) #OC30052017 + + #DEBUG + #if(i == 48): + # arI1 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" 2D array to take intensity data + # srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) + # srwl_uti_save_intens_ascii(arI1, wfr.mesh, os.path.join(os.getcwd(), 'data_CDI', 'debug_int_se.dat')) + #END DEBUG + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #print('DEBUG: Commented-out: CalcElecFieldSR') + #print('DEBUG MESSAGE: CalcElecFieldSR called (rank:', rank,')') + + if(_opt_bl is not None): + + #print('Wavefront propagation calculation ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #if(_w_wr != 0.): #OC26032016 + if(_wr != 0.): #OC07092016 + wfr.Rx = _wr + wfr.Ry = _wr + + if(_wre > 0.): #OC05012017 + wfr.dRx = _wre + wfr.dRy = _wre - if(_opt_bl != None): srwl.PropagElecField(wfr, _opt_bl) #propagate Electric Field emitted by the electron + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #print('DEBUG: Commented-out: PropagElecField') + + #DEBUG + #if(i == 48): + # arI1 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" 2D array to take intensity data + # srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) + # srwl_uti_save_intens_ascii(arI1, wfr.mesh, os.path.join(os.getcwd(), 'data_CDI', 'debug_int_pr_se.dat')) + # sys.exit() + #END DEBUG + if(_pres_ang > 0): + wfr.unitElFldAng = 1 #OC20112017 (to have result in [ph/s/.1%bw/mrad^2] vs [rad]) srwl.SetRepresElecField(wfr, 'a') + if(wfr2 is not None): + wfr2.unitElFldAng = 1 #OC20112017 + srwl.SetRepresElecField(wfr2, 'a') + + #print('DEBUG: Commented-out: SetRepresElecField') except: traceback.print_exc() - if(workStokes == None): - workStokes = SRWLStokes(1, 'f', wfr.mesh.eStart, wfr.mesh.eFin, wfr.mesh.ne, wfr.mesh.xStart, wfr.mesh.xFin, wfr.mesh.nx, wfr.mesh.yStart, wfr.mesh.yFin, wfr.mesh.ny) - else: - nPtCur = wfr.mesh.ne*wfr.mesh.nx*wfr.mesh.ny*4 - if(len(workStokes.arS) < nPtCur): - del workStokes.arS - workStokes.arS = array('f', [0]*nPtCur) - #workStokes.mesh.set_from_other(wfr.mesh) + meshWork = deepcopy(wfr.mesh) + meshWork2 = None #OC30052017 + if(doMutual > 0): + if(_char == 2): + meshWork.ny = 1 + meshWork.yStart = _y0 + meshWork.yFin = _y0 + elif(_char == 3): + meshWork.nx = 1 + meshWork.xStart = _x0 + meshWork.xFin = _x0 + elif(_char == 4): #OC30052017 #Cuts of Mutual Intensity vs X & Y + meshWork.ny = 1 + meshWork.yStart = _y0 + meshWork.yFin = _y0 + meshWork2 = deepcopy(wfr.mesh) + meshWork2.nx = 1 + meshWork2.xStart = _x0 + meshWork2.xFin = _x0 + + #OC06042017 (commented-out the above, entered workStokes = ... below) + workStokes = SRWLStokes(1, 'f', meshWork.eStart, meshWork.eFin, meshWork.ne, meshWork.xStart, meshWork.xFin, meshWork.nx, meshWork.yStart, meshWork.yFin, meshWork.ny, doMutual) + + if(_char == 4): #Cuts of Mutual Intensity vs X & Y + workStokes2 = SRWLStokes(1, 'f', meshWork2.eStart, meshWork2.eFin, meshWork2.ne, meshWork2.xStart, meshWork2.xFin, meshWork2.nx, meshWork2.yStart, meshWork2.yFin, meshWork2.ny, doMutual) + + if(_char == 40): #OC03052018 #Intensity and Cuts of Mutual Intensity vs X & Y + workStokes2 = SRWLStokes(1, 'f', meshWork.eStart, meshWork.eFin, meshWork.ne, meshWork.xStart, meshWork.xFin, meshWork.nx, _y0, _y0, 1, _mutual=1) + workStokes3 = SRWLStokes(1, 'f', meshWork.eStart, meshWork.eFin, meshWork.ne, _x0, _x0, 1, meshWork.yStart, meshWork.yFin, meshWork.ny, _mutual=1) + + if(_me_approx == 0): #OC05042017 #General case of numerical integration over 5D phase space of electron beam + + if(_char == 20): + wfr.copy_comp(workStokes) #OC15012017: copy electric field components to Stokes structure + elif(_char == 0): #OC15092017 + srwl.CalcIntFromElecField(workStokes.arS, wfr, 6, 0, depTypeInt, phEnInt, 0., 0.) + else: + wfr.calc_stokes(workStokes, _n_stokes_comp=numComp) #calculate Stokes parameters from Electric Field + if(workStokes2 is not None): #OC30052017 + if(wfr2 is None): wfr.calc_stokes(workStokes2, _n_stokes_comp=numComp) + else: wfr2.calc_stokes(workStokes2, _n_stokes_comp=numComp) + + if(workStokes3 is not None): #OC03052018 + wfr.calc_stokes(workStokes3, _n_stokes_comp=numComp) + + elif(_me_approx == 1): #OC05042017 #Numerical integration only over electron energy, convolution over transverse phase space + + if(_char == 0): #Total intensity + #DEBUG + #print('DEBUG: 2nd order e-beam moments after eventual propagation:') + #print('sigX=', sqrt(wfr.partBeam.arStatMom2[0])) + #print('mXXp=', wfr.partBeam.arStatMom2[1]) + #print('sigXp=', sqrt(wfr.partBeam.arStatMom2[2])) + #print('sigY=', sqrt(wfr.partBeam.arStatMom2[3])) + #print('mYYp=', wfr.partBeam.arStatMom2[4]) + #print('sigYp=', sqrt(wfr.partBeam.arStatMom2[5])) + #print('relEnSpr=', sqrt(wfr.partBeam.arStatMom2[10])) + #print('wfr.Rx=', wfr.Rx, ' wfr.Ry=', wfr.Ry) + #print('wfr.arElecPropMatr=', wfr.arElecPropMatr) + #END DEBUG + + #srwl.CalcIntFromElecField(workStokes.arS, wfr, 6, 1, depTypeME_Approx, phEnME_Approx, _x0, _y0) + srwl.CalcIntFromElecField(workStokes.arS, wfr, 6, 1, depTypeInt, phEnInt, _x0, _y0) #OC30052017 + + #DEBUG + #arTest = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) + ##srwl.CalcIntFromElecField(arTest, wfr, 6, 1, depTypeME_Approx, phEnME_Approx, _x0, _y0) + #srwl.CalcIntFromElecField(arTest, wfr, 6, 0, depTypeME_Approx, phEnME_Approx, _x0, _y0) - wfr.calc_stokes(workStokes) #calculate Stokes parameters from Electric Field + #srwl_uti_save_intens_ascii(arTest, wfr.mesh, _file_path + '.debug', numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) - if(resStokes == None): - resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny) + ##srwl_uti_save_intens_ascii(workStokes.arS, workStokes.mesh, _file_path + '.debug', numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) + #if(i == 0): raise Exception("DEBUG: STOP") #OC06042017 + ##srwl.CalcIntFromElecField(workStokes.arS, wfr, 6, 0, depTypeME_Approx, phEnME_Approx, _x0, _y0) + #END DEBUG + + #elif(_char == 1): #Four Stokes components + #To implement extraction of Stokes components, with and without convolution, in CalcIntFromElecField + + #DEBUG + #srwl_uti_save_intens_ascii(workStokes.arS, workStokes.mesh, _file_path, 1) + #END DEBUG + + if(resStokes is None): + resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) + #DEBUG + #print('resStokes #2: ne=', resStokes.mesh.ne, 'eStart=', resStokes.mesh.eStart, 'eFin=', resStokes.mesh.eFin) + #END DEBUG + + if(_char == 4): #OC31052017 #Cuts of Mutual Intensity vs X & Y + if(resStokes2 is None): + resStokes2 = SRWLStokes(1, 'f', meshRes2.eStart, meshRes2.eFin, meshRes2.ne, meshRes2.xStart, meshRes2.xFin, meshRes2.nx, meshRes2.yStart, meshRes2.yFin, meshRes2.ny, doMutual) + if(arAuxResSt12 is None): + lenArSt12 = len(resStokes.arS) + len(resStokes2.arS) + arAuxResSt12 = array('f', [0]*lenArSt12) + + if(_char == 40): #OC03052018 #Intensity and Cuts of Mutual Intensity vs X & Y + if(resStokes2 is None): + resStokes2 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, _y0, _y0, 1, _mutual=1) + if(resStokes3 is None): + resStokes3 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, _x0, _x0, 1, meshRes.yStart, meshRes.yFin, meshRes.ny, _mutual=1) + if(arAuxResSt123 is None): + lenArSt123 = len(resStokes.arS) + len(resStokes2.arS) + len(resStokes3.arS) + arAuxResSt123 = array('f', [0]*lenArSt123) + + #DEBUG + #print('workStokes.mesh: nx=', workStokes.mesh.nx, 'xStart=', workStokes.mesh.xStart, 'xFin=', workStokes.mesh.xFin) + #print('workStokes.mesh: ny=', workStokes.mesh.ny, 'yStart=', workStokes.mesh.yStart, 'yFin=', workStokes.mesh.yFin) + #print('resStokes.mesh: nx=', resStokes.mesh.nx, 'xStart=', resStokes.mesh.xStart, 'xFin=', resStokes.mesh.xFin) + #print('resStokes.mesh: ny=', resStokes.mesh.ny, 'yStart=', resStokes.mesh.yStart, 'yFin=', resStokes.mesh.yFin) + #END DEBUG - if(_opt_bl == None): - resStokes.avg_update_same_mesh(workStokes, iAvgProc, 1) + if(_opt_bl is None): + #resStokes.avg_update_same_mesh(workStokes, iAvgProc, 1) + + #print('resStokes.avg_update_same_mesh ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #resStokes.avg_update_same_mesh(workStokes, iAvgProc, 1, ePhIntegMult) #to treat all Stokes components / Polarization in the future + resStokes.avg_update_same_mesh(workStokes, iAvgProc, numComp, ePhIntegMult) #OC16012017 #to treat all Stokes components / Polarization in the future + + if((resStokes2 is not None) and (workStokes2 is not None)): #OC30052017 + resStokes2.avg_update_same_mesh(workStokes2, iAvgProc, numComp, ePhIntegMult) + + if((resStokes3 is not None) and (workStokes3 is not None)): #OC03052018 + resStokes3.avg_update_same_mesh(workStokes3, iAvgProc, numComp, ePhIntegMult) + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #DEBUG + #srwl_uti_save_intens_ascii(workStokes.arS, workStokes.mesh, _file_path, 1) + #END DEBUG + else: #print('DEBUG MESSAGE: Started interpolation of current wavefront on resulting mesh') - resStokes.avg_update_interp(workStokes, iAvgProc, 1, 1) + #if(doMutual <= 0): resStokes.avg_update_interp(workStokes, iAvgProc, 1, 1) + #else: resStokes.avg_update_interp_mutual(workStokes, iAvgProc, 1) + + #print('resStokes.avg_update_interp ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #DEBUG (test save at iAvgProc = 0) + #if(iAvgProc == 0): + # srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) + #END DEBUG + + #if(doMutual <= 0): resStokes.avg_update_interp(workStokes, iAvgProc, 1, 1, ePhIntegMult) #to treat all Stokes components / Polarization in the future + + if(_char == 40): #OC03052018 + resStokes.avg_update_interp(workStokes, iAvgProc, 1, numComp, ePhIntegMult) + + if((resStokes2 is not None) and (workStokes2 is not None)): + resStokes2.avg_update_interp_mutual(workStokes2, iAvgProc, 1, ePhIntegMult) + + if((resStokes3 is not None) and (workStokes3 is not None)): + resStokes3.avg_update_interp_mutual(workStokes3, iAvgProc, 1, ePhIntegMult) + + else: + if(doMutual == 0): resStokes.avg_update_interp(workStokes, iAvgProc, 1, numComp, ePhIntegMult) #OC16012017 #to treat all Stokes components / Polarization in the future + else: + resStokes.avg_update_interp_mutual(workStokes, iAvgProc, 1, ePhIntegMult) + + if((resStokes2 is not None) and (workStokes2 is not None)): #OC30052017 + resStokes2.avg_update_interp_mutual(workStokes2, iAvgProc, 1, ePhIntegMult) + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG #print('DEBUG MESSAGE: Finished interpolation of current wavefront on resulting mesh') iAvgProc += 1 if(iAvgProc >= _n_part_avg_proc): if(nProc > 1): #sys.exit(0) - comMPI.Send([resStokes.arS, MPI.FLOAT], dest=0) + #print("sending data from %d to 0" % rank) #an he + #DEBUG + #srwl_uti_save_intens_ascii(resStokes.arS, resStokes.mesh, _file_path, 1) + #END DEBUG + + #DEBUG + #srwl_uti_save_text("Preparing to sending # " + str(iAuxSendCount + 1), _file_path + "." + str(rank) + "bs.dbg") + #END DEBUG + + #comMPI.Send([resStokes.arS, MPI.FLOAT], dest=0) + if(resStokes2 is None): comMPI.Send([resStokes.arS, MPI.FLOAT], dest=0) + #else: #OC31052017 + elif(resStokes3 is None): #OC03052018 + lenArSt1 = len(resStokes.arS) + lenArSt2 = len(resStokes2.arS) + for i1 in range(lenArSt1): arAuxResSt12[i1] = resStokes.arS[i1] + for i2 in range(lenArSt2): arAuxResSt12[i2 + lenArSt1] = resStokes2.arS[i2] + comMPI.Send([arAuxResSt12, MPI.FLOAT], dest=0) + else: #OC03052018 + lenArSt1 = len(resStokes.arS) + lenArSt2 = len(resStokes2.arS) + lenArSt3 = len(resStokes3.arS) + for i1 in range(lenArSt1): arAuxResSt123[i1] = resStokes.arS[i1] + for i2 in range(lenArSt2): arAuxResSt123[i2 + lenArSt1] = resStokes2.arS[i2] + lenArSt12 = lenArSt1 + lenArSt2 + for i3 in range(lenArSt3): arAuxResSt123[i3 + lenArSt12] = resStokes3.arS[i3] + comMPI.Send([arAuxResSt123, MPI.FLOAT], dest=0) + + #if(resStokes2 is not None): comMPI.Send([resStokes2.arS, MPI.FLOAT], dest=0) #OC30052017 + + iAuxSendCount += 1 #for debug + + #DEBUG + #srwl_uti_save_text("Sent # " + str(iAuxSendCount), _file_path + "." + str(rank) + "es.dbg") + #END DEBUG + for ir in range(nStPt): resStokes.arS[ir] = 0 + + if(resStokes2 is not None): #OC30052017 + for ir in range(nStPt2): + resStokes2.arS[ir] = 0 + + if(resStokes3 is not None): #OC03052018 + for ir in range(nStPt3): + resStokes3.arS[ir] = 0 + + #DEBUG + #srwl_uti_save_intens_ascii(resStokes.arS, resStokes.mesh, _file_path, 1) + #END DEBUG + iAvgProc = 0 if(nProc == 1): @@ -1827,33 +6880,511 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ # sys.exit(0) #END DEBUG iSave += 1 - if((_file_path != None) and (iSave == _n_save_per)): + if((_file_path is not None) and (iSave == _n_save_per)): #Saving results from time to time in the process of calculation: - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1) + + #print('srwl_uti_save_intens_ascii ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _mutual = doMutual) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC26042016 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + + if(_char == 40): #OC03052018 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + if(resStokes2 is not None): + #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + if(resStokes3 is not None): + #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + elif(_char == 4): #OC03052018 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) #OC06052018 + else: + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + + #DEBUG + #srwl_uti_save_intens_ascii(workStokes.arS, workStokes.mesh, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) + #END DEBUG + + #MR01112016: write the status of the simulation: + srwl_uti_save_stat_wfr_emit_prop_multi_e(i + 1, total_num_of_particles, filename=log_path) + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #sys.exit(0) iSave = 0 elif((rank == 0) and (nProc > 1)): - #sys.exit(0) - nRecv = int(nPartPerProc*nProc/_n_part_avg_proc + 1e-09) + #nRecv = int(nPartPerProc*nProc/_n_part_avg_proc + 1e-09) + nRecv = nSentPerProc*(nProc - 1) #Total number of sending acts to be made by all worker processes, and to be received by master + + #print('DEBUG MESSAGE: Actual number of macro-electrons:', nRecv*_n_part_avg_proc) + + #DEBUG + #srwl_uti_save_text("nRecv: " + str(nRecv) + " nPartPerProc: " + str(nPartPerProc) + " nProc: " + str(nProc) + " _n_part_avg_proc: " + str(_n_part_avg_proc), _file_path + ".00.dbg") + #END DEBUG + + if(resStokes is None): + resStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) + if(workStokes is None): + workStokes = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, meshRes.yStart, meshRes.yFin, meshRes.ny, doMutual) + + if(_char == 4): #OC30052017 #Cuts of Mutual Intensity vs X & Y + if(resStokes2 is None): + resStokes2 = SRWLStokes(1, 'f', meshRes2.eStart, meshRes2.eFin, meshRes2.ne, meshRes2.xStart, meshRes2.xFin, meshRes2.nx, meshRes2.yStart, meshRes2.yFin, meshRes2.ny, doMutual) + if(arAuxResSt12 is None): + lenArResSt12 = len(resStokes.arS) + len(resStokes2.arS) + arAuxResSt12 = array('f', [0]*lenArResSt12) + + if(workStokes2 is None): + workStokes2 = SRWLStokes(1, 'f', meshRes2.eStart, meshRes2.eFin, meshRes2.ne, meshRes2.xStart, meshRes2.xFin, meshRes2.nx, meshRes2.yStart, meshRes2.yFin, meshRes2.ny, doMutual) + if(arAuxWorkSt12 is None): + lenArWorkSt12 = len(workStokes.arS) + len(workStokes2.arS) + arAuxWorkSt12 = array('f', [0]*lenArWorkSt12) + + if(_char == 40): #OC03052018 #Intensity and Cuts of Mutual Intensity vs X & Y + if(resStokes2 is None): + resStokes2 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, _y0, _y0, 1, _mutual=1) + if(resStokes3 is None): + resStokes3 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, _x0, _x0, 1, meshRes.yStart, meshRes.yFin, meshRes.ny, _mutual=1) + if(arAuxResSt123 is None): + lenArResSt123 = len(resStokes.arS) + len(resStokes2.arS) + len(resStokes3.arS) + arAuxResSt123 = array('f', [0]*lenArResSt123) + + if(workStokes2 is None): + workStokes2 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, meshRes.xStart, meshRes.xFin, meshRes.nx, _y0, _y0, 1, _mutual=1) + if(workStokes3 is None): + workStokes3 = SRWLStokes(1, 'f', meshRes.eStart, meshRes.eFin, meshRes.ne, _x0, _x0, 1, meshRes.yStart, meshRes.yFin, meshRes.ny, _mutual=1) + if(arAuxWorkSt123 is None): + lenArWorkSt123 = len(workStokes.arS) + len(workStokes2.arS) + len(workStokes3.arS) + arAuxWorkSt123 = array('f', [0]*lenArWorkSt123) + for i in range(nRecv): #loop over messages from workers - comMPI.Recv([workStokes.arS, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + #DEBUG + #srwl_uti_save_text("Preparing to receiving # " + str(i), _file_path + ".br.dbg") + #END DEBUG + + #comMPI.Recv([workStokes.arS, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + if(workStokes2 is None): #OC31052017 + comMPI.Recv([workStokes.arS, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + #else: + elif(workStokes3 is None): #OC03052018 + comMPI.Recv([arAuxWorkSt12, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + + lenArWorkSt1 = len(workStokes.arS) + for i1 in range(lenArWorkSt1): workStokes.arS[i1] = arAuxWorkSt12[i1] + lenArWorkSt2 = len(workStokes2.arS) + for i2 in range(lenArWorkSt2): workStokes2.arS[i2] = arAuxWorkSt12[i2 + lenArWorkSt1] + + else: #OC03052018 + comMPI.Recv([arAuxWorkSt123, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + + lenArWorkSt1 = len(workStokes.arS) + for i1 in range(lenArWorkSt1): workStokes.arS[i1] = arAuxWorkSt123[i1] + lenArWorkSt2 = len(workStokes2.arS) + for i2 in range(lenArWorkSt2): workStokes2.arS[i2] = arAuxWorkSt123[i2 + lenArWorkSt1] + lenArWorkSt3 = len(workStokes3.arS) + lenArWorkSt12 = lenArWorkSt1 + lenArWorkSt2 + for i3 in range(lenArWorkSt3): workStokes3.arS[i3] = arAuxWorkSt123[i3 + lenArWorkSt12] + + #if((_char == 4) and (workStokes2 is not None)): #OC30052017 #Cuts of Mutual Intensity vs X & Y + # comMPI.Recv([workStokes2.arS, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + + #MR20160907 #Save .log and .json files: + particle_number = (i + 1) * _n_part_avg_proc + #srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles) + srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles, filename=log_path) + + #DEBUG + #srwl_uti_save_text("Received intensity # " + str(i), _file_path + ".er.dbg") + #END DEBUG + + #resStokes.avg_update_same_mesh(workStokes, i + 1) + #resStokes.avg_update_same_mesh(workStokes, i + 1, 1, ePhIntegMult) #to treat all Stokes components / Polarization in the future + multFinAvg = 1 if(_n_part_avg_proc > 1) else ePhIntegMult #OC120714 fixed: the normalization may have been already applied at the previous avaraging on each worker node! + + #print('resStokes.avg_update_same_mesh ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #DEBUG (test save at i = 0) + #if(i == 0): + # srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) + #END DEBUG + + #resStokes.avg_update_same_mesh(workStokes, i + 1, 1, multFinAvg) #in the future treat all Stokes components / Polarization, not just s0! + #resStokes.avg_update_same_mesh(workStokes, i, 1, multFinAvg) #OC15012017 #in the future treat all Stokes components / Polarization, not just s0! + resStokes.avg_update_same_mesh(workStokes, i, numComp, multFinAvg) #OC15012017 #in the future treat all Stokes components / Polarization, not just s0! + + if((resStokes2 is not None) and (workStokes2 is not None)): + resStokes2.avg_update_same_mesh(workStokes2, i, numComp, multFinAvg) #OC30052017 #in the future treat all Stokes components / Polarization, not just s0! + + if((resStokes3 is not None) and (workStokes3 is not None)): + resStokes3.avg_update_same_mesh(workStokes3, i, numComp, multFinAvg) #OC03052018 #in the future treat all Stokes components / Polarization, not just s0! - resStokes.avg_update_same_mesh(workStokes, i + 1) + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #DEBUG + #srwl_uti_save_text("Updated Stokes after receiving intensity # " + str(i), _file_path + "." + str(i) + "er.dbg") + #END DEBUG iSave += 1 if(iSave == _n_save_per): #Saving results from time to time in the process of calculation - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1) + + #print('srwl_uti_save_intens_ascii ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG + + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _mutual = doMutual) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC26042016 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + + if(_char == 40): #OC03052018 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + if(resStokes2 is not None): + #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + if(resStokes3 is not None): + #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 + srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + elif(_char == 4): #OC03052018 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 + srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + if((resStokes2 is not None) and (meshRes2 is not None)): + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) + else: + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC30052017 + if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + + #DEBUG + #srwl_uti_save_intens_ascii(workStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + #END DEBUG + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + iSave = 0 + #DEBUG + #srwl_uti_save_text("Exiting srwl_wfr_emit_prop_multi_e", _file_path + "." + str(rank) + "e.dbg") + #END DEBUG if((rank == 0) or (nProc == 1)): #Saving final results: - if(_file_path != None): - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1) + #if(_file_path != None): + #if(file_path1 is not None): #OC30052017 + + #print('srwl_uti_save_intens_ascii ... ', end='') #DEBUG + #t0 = time.time(); #DEBUG - return resStokes + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _mutual = doMutual) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC26042016 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + + if(_char == 40): #OC03052018 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + if(resStokes2 is not None): + #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + if(resStokes3 is not None): + #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) + srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + elif(_char == 4): #OC03052018 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + if((resStokes2 is not None) and (meshRes2 is not None)): + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) + else: + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC16012017 + if((resStokes2 is not None) and (meshRes2 is not None)): #OC03052018 + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC16012017 + + #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG + #return resStokes + if(resStokes2 is None): #OC30052017 + return resStokes + #else: + elif(resStokes3 is None): #OC03052018 + return resStokes, resStokes2 + else: + return resStokes, resStokes2, resStokes3 else: return None + +#**************************************************************************** +#**************************************************************************** +#Import of modules requiring classes defined in this smodule +#**************************************************************************** +#**************************************************************************** +from srwl_uti_src import * + +#**************************************************************************** +#**************************************************************************** +# Help to main functions implemented in C/C++ (available through srwlpy.pyd/.so) +#**************************************************************************** +#**************************************************************************** +helpCalcMagnField = """CalcMagnField(_outMagFld3DC, _inMagFldC, _inPrec) +function calculates (tabulates) 3D magnetic field created by different magnetic field sources / elements +:param _outMagFld3DC: output magnetic field container (instance of SRWLMagFldC) with the tabulated 3D magnetic field element + (instance of SRWLMagFld3D) +:param _inMagFldC: input magnetic field container (instance of SRWLMagFldC) of magnetic field sources / elements +:param _inPrec: optional array of precision parameters + _precPar[0] defines the type of calculation: =0 -standard calculation, =1 -interpolation vs one parameter, =2 -interpolation vs two parameters + _precPar[1]: first parameter value the field has to be interpolated for + _precPar[2]: second parameter value the field has to be interpolated for + _precPar[3]: specifies type of interpolation: =1 -(bi-)linear, =2 -(bi-)quadratic, =3 -(bi-)cubic +""" +helpCalcPartTraj = """CalcPartTraj(_prtTrj, _inMagFldC, _inPrec) +function calculates charged particle trajectory in external 3D magnetic field (in Cartesian laboratory frame) +:param _prtTrj: input / output trajectory structure (instance of SRWLPrtTrj); + note that all data arrays should be allocated in Python script before calling this function; + initial conditions and particle type must be specified in _prtTrj.partInitCond; + the initial conditions are assumed to be given for ct = 0, + however the trajectory will be calculated for the mesh defined by _prtTrj.np, _prtTrj.ctStart, _prtTrj.ctEnd +:param _inMagFldC: input magnetic field container structure (instance of SRWLMagFldC) +:param _inPrec: input list of calculation method ID and precision parameters; + _inPrec[0]: integration method ID: + =1 -use the fourth-order Runge-Kutta (R-K), with the precision driven by number of points + =2 -use the fifth-order R-K + _inPrec[1],[2],[3],[4],[5]: optional absolute precision values for X[m],X'[rad],Y[m],Y'[rad],Z[m] + to be taken into account only for R-K fifth order or higher (yet to be tested!!) + _inPrec[6]: tolerance (default = 1) for R-K fifth order or higher + _inPrec[7]: maximal number of auto-steps for R-K fifth order or higher (default = 5000) +""" +helpCalcPartTrajFromKickMatr = """CalcPartTrajFromKickMatr(_prtTrj, _inKickM, _inPrec) +function calculates charged particle trajectory from one or a list of kick-matrices +:param _prtTrj: input / output trajectory structure (instance of SRWLPrtTrj); + note that all data arrays should be allocated in Python script before calling this function; + initial conditions and particle type must be specified in _partTraj.partInitCond; + the initial conditions are assumed to be given for ct = 0, + however the trajectory will be calculated for the mesh defined by _prtTrj.np, _prtTrj.ctStart, _prtTrj.ctEnd +:param _inKickM: input kick-matrix (instance of SRWLKickM) or a list of such kick-matrices +:param _inPrec: input list of calculation parameters: + _inPrec[0]: switch specifying whether the new trajectory data should be added to pre-existing trajectory data (=1, default) + or it should override any pre-existing trajectory data (=0) +""" +helpCalcElecFieldSR = """CalcElecFieldSR(_wfr, _inPrtTrj, _inMagFldC, _inPrec) +function calculates Electric Field (Wavefront) of Synchrotron Radiation by a relativistic charged particle +traveling in external 3D magnetic field +:param _wfr: input / output resulting Wavefront structure (instance of SRWLWfr); + all data arrays should be allocated in Python script before calling this function; + the emitting particle beam, radiation mesh, presentation, etc., should be specified in this structure at input +:param _inPrtTrj: optional input pre-calculated particle trajectory structure (instance of SRWLPrtTrj); + the initial conditions and particle type must be specified in _inPrtTrj.partInitCond; + if the trajectory data arrays (_inPrtTrj.arX, _inPrtTrj.arXp, _inPrtTrj.arY, _inPrtTrj.arYp) are defined, + the SR will be calculated from these data; if these arrays are not defined, or if _inPrtTrj =0, the function will attempt + to calculate the SR from the magnetic field data (_inMagFldC) which has to be supplied +:param _inMagFldC: optional input magnetic field (container) structure (instance of SRWLMagFldC); + to be taken into account only if particle trajectroy arrays (_inPrtTrj.arX, _inPrtTrj.arXp, _inPrtTrj.arY, _inPrtTrj.arYp) + are not defined +:param _inPrec: input list of precision parameters: + _inPrec[0]: method ID: =0 -"manual", =1 -"auto-undulator", =2 -"auto-wiggler") + _inPrec[1]: step size (for "manual" method, i.e. if _inPrec[0]=0) or relative precision + (for "auto-undulator" or "auto-wiggler" methods, i.e. if _inPrec[0]=1 or _inPrec[0]=2) + _inPrec[2]: longitudinal position [m] to start integration (effective if _inPrec[2] < _inPrec[3]) + _inPrec[3]: longitudinal position [m] to finish integration (effective if _inPrec[2] < _inPrec[3]) + _inPrec[4]: number of points to use for trajectory calculation + _inPrec[5]: calculate terminating terms or not: + =0 -don't calculate two terms, + =1 -do calculate two terms, + =2 -calculate only upstream term, + =3 -calculate only downstream term + _inPrec[6]: sampling factor (for propagation, effective if > 0) +""" +helpCalcElecFieldGaussian = """CalcElecFieldGaussian(_wfr, _inGsnBm, _inPrec) +function calculates Electric Field (Wavefront) of a coherent Gaussian beam +:param _wfr: input / output resulting Wavefront structure (instance of SRWLWfr); + all data arrays should be allocated in Python script before calling this function; + the emitting particle beam, radiation mesh, presentation, etc., should be specified in this structure at input +:param _inGsnBm: input coherent Gaussian beam parameters structure (instance of SRWLGsnBm) +:param _inPrec: input list of precision parameters: + _inPrec[0]: sampling factor (for propagation, effective if > 0) +""" +helpCalcElecFieldPointSrc = """CalcElecFieldPointSrc(_wfr, _inPtSrc, _inPrec) +function calculates Electric Field (Wavefront) of a Pont Source (i.e. spherical wave) +:param _wfr: input / output resulting Wavefront structure (instance of SRWLWfr); + all data arrays should be allocated in a calling function/application; + the mesh, presentation, etc., should be specified in this structure at input +:param _inPtSrc: input Point Source parameters structure (instance of SRWLPtSrc) +:param _inPrec: input list of precision parameters: + _inPrec[0]: sampling factor (for propagation, effective if > 0) +""" +helpCalcStokesUR = """CalcStokesUR(_stk, _inElBeam, _inUnd, _inPrec) +function calculates Stokes parameters of Undulator Radiation (UR) by a relativistic finite-emittance electron beam +traveling in periodic magnetic field of an undulator +:param _stk: input / output resulting Stokes structure (instance of SRWLStokes); + all data arrays should be allocated in Python script before calling this function; the mesh, presentation, etc., + should be specified in this structure at input +:param _inElBeam: input electron beam structure (instance of SRWLPartBeam) +:param _inUnd: input undulator (periodic magnetic field) structure (instance of SRWLMagFldU) +:param _inPrec: input list of precision parameters: + _inPrec[0]: initial harmonic of UR spectrum + _inPrec[1]: final harmonic of UR spectrum + _inPrec[2]: longitudinal integration precision parameter (nominal value is 1.0, for better accuracy make it > 1.0) + _inPrec[3]: azimuthal integration precision parameter (nominal value is 1.0, for better accuracy make it > 1.0) + _inPrec[4]: calculate flux (=1) or intensity (=2) +""" +helpCalcPowDenSR = """CalcPowDenSR(_stk, _inElBeam, _inPrtTrj, _inMagFldC, _inPrec) +function calculates Power Density distribution of Synchrotron Radiation by a relativistic finite-emittance electron beam +traveling in arbitrary magnetic field +:param _stk: input / output resulting Stokes structure (instance of SRWLStokes); + all data arrays should be allocated in Python script before calling this function; the mesh, presentation, etc., + should be specified in this structure at input; the Power Density data will be written to _stk.arS +:param _inElBeam: input electron beam structure (instance of SRWLPartBeam) +:param _inPrtTrj: input trajectory structure (instance of SRWLPrtTrj); + can be =0; in such case, the power density is calculated based on _inElBeam and _inMagFldC +:param _inMagFldC: input magnetic field container structure (instance of SRWLMagFldC); + can be =0; in such case, power density is calculated from _inPrtTrj (if _inPrtTrj != 0) and _inElBeam (if _inElBeam != 0)) +:param _inPrec: input list of precision parameters: + _inPrec[0]: precision factor (=1.0 default, >1.0 for more precision) + _inPrec[1]: power density computation method (=1 -"near field" (default), =2 -"far field") + _inPrec[2]: initial longitudinal position [m] (effective if < _inPrec[3]) + _inPrec[3]: final longitudinal position [m] (effective if > _inPrec[2]) + _inPrec[4]: number of points to use for trajectory calculation +""" +helpCalcIntFromElecField = """CalcIntFromElecField(_arI, _inWfr, _inPol, _inIntType, _inDepType, _inE, _inX, _inY) +function calculates/"extracts" Intensity from pre-calculated Electric Field +:param _arI: output resulting Intensity array (should be allocated in Python script before calling this function) +:param _inWfr: input pre-calculated Wavefront structure (instance of SRWLWfr) +:param _inPol: input switch specifying polarization component to be extracted: + =0 -Linear Horizontal; + =1 -Linear Vertical; + =2 -Linear 45 degrees; + =3 -Linear 135 degrees; + =4 -Circular Right; + =5 -Circular Left; + =6 -Total +:param _inIntType: input switch specifying "type" of a characteristic to be extracted: + =0 -"Single-Electron" Intensity; + =1 -"Multi-Electron" Intensity; + =2 -"Single-Electron" Flux; + =3 -"Multi-Electron" Flux; + =4 -"Single-Electron" Radiation Phase; + =5 -Re(E): Real part of Single-Electron Electric Field; + =6 -Im(E): Imaginary part of Single-Electron Electric Field; + =7 -"Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence) +:param _inDepType: input switch specifying type of dependence to be extracted: + =0 -vs e (photon energy or time); + =1 -vs x (horizontal position or angle); + =2 -vs y (vertical position or angle); + =3 -vs x&y (horizontal and vertical positions or angles); + =4 -vs e&x (photon energy or time and horizontal position or angle); + =5 -vs e&y (photon energy or time and vertical position or angle); + =6 -vs e&x&y (photon energy or time, horizontal and vertical positions or angles); +:param _inE: input photon energy [eV] or time [s] to keep fixed (to be taken into account for dependences vs x, y, x&y) +:param _inX: input horizontal position [m] to keep fixed (to be taken into account for dependences vs e, y, e&y) +:param _inY: input vertical position [m] to keep fixed (to be taken into account for dependences vs e, x, e&x) +""" +helpResizeElecField = """ResizeElecField(_wfr, _inType, _inPar) +function resizes Electric Field Wavefront vs transverse positions / angles or photon energy / time +:param _wfr: input / output Wavefront structure (instance of SRWLWfr) +:param _inType: input character specifying whether the resizing should be done vs positions / angles ('c') + or vs photon energy / time ('f') +:param _inPar: input list of parameters (meaning depends on value of _inType): + if(_inType == 'c'): + _inPar[0]: method (=0 -regular method, without FFT, =1 -"special" method involving FFT) + _inPar[1]: range resizing factor for horizontal position / angle + (range will be decreased if 0 < _inPar[1] < 1. and increased if _inPar[1] > 1.) + _inPar[2]: resolution resizing factor for horizontal position / angle + (resolution will be decreased if 0 < _inPar[2] < 1. and increased if _inPar[2] > 1.) + _inPar[3]: range resizing factor for vertical position / angle + (range will be decreased if 0 < _inPar[3] < 1. and increased if _inPar[3] > 1.) + _inPar[4]: resolution resizing factor for vertical position / angle + (resolution will be decreased if 0 < _inPar[4] < 1. and increased if _inPar[4] > 1.) + _inPar[5]: relative horizontal wavefront center position / angle at resizing + (default is 0.5; in that case the resizing will be symmetric) + _inPar[6]: relative vertical wavefront center position / angle at resizing + (default is 0.5; in that case the resizing will be symmetric) + if(_inType == 'f'): + _inPar[0]: method (=0 -regular method, without FFT, =1 -"special" method involving FFT) + _inPar[1]: range resizing factor for photon energy / time + (range will be decreased if 0 < _inPar[1] < 1. and increased if _inPar[1] > 1.) + _inPar[2]: resolution resizing factor for photon energy / time + (resolution will be decreased if 0 < _inPar[2] < 1. and increased if _inPar[2] > 1.) + _inPar[3]: relative photon energy / time center position at resizing + (default is 0.5; in that case the resizing will be symmetric) +""" +helpSetRepresElecField = """SetRepresElecField(_wfr, _inRepr) +function changes Representation of Electric Field: positions <-> angles, frequency <-> time +:param _wfr: input / output Wavefront structure (instance of SRWLWfr) +:param _inRepr: input character specifying desired representation: + ='c' for coordinate, ='a' for angle, ='f' for frequency, ='t' for time +""" +helpPropagElecField = """PropagElecField(_wfr, _inOptC) +function propagates Electric Field Wavefront through Optical Elements and free space +:param _wfr: input / output Wavefront structure (instance of SRWLWfr) +:param _inOptC: input container of optical elements (instance of SRWLOptC) the propagation should be done through; + note that lists of optical elements and the corresponding propagation parameters have to be defined in + _inOptC.arOpt and _inOptC.arProp respectively (see help/comments to SRWLOptC class) +""" +helpUtiFFT = """UtiFFT(_data, _mesh, _inDir) +function performs 1D or 2D in-place Fast Fourier Transform (as defined by arguments) +:param _data: input / output float (single-precision) type array of data to be Fourier-transformed; + in the case of a 2D transform, the data should be "C-aligned" in 1D array, + with the first dimension being "inner" (i.e. most frequently changing); + the FFT is performed "in place", i.e. the input _data will be replaced by a resulting data +:param _mesh: input / output list specifying (equidistant, regular) mesh of the data to be transformed: + _mesh[0]: start value of the first argument + _mesh[1]: step size value of the first argument + _mesh[2]: number of points over the first argument (note: it should be even!) + _mesh[3]: (optional, to be used for 2D FFT) start value of the second argument + _mesh[4]: (optional, to be used for 2D FFT) step size value of the second argument + _mesh[5]: (optional, to be used for 2D FFT) number of points of the second argument (note: it should be even!) + if len(_mesh) == 3, 1D FFT will be performed + else if len(_mesh) == 6, 2D FFT will be performed + the input _mesh will be replaced by a resulting mesh +:param _inDir: input integer number specifying FFT "direction": >0 means forward FFT, <0 means backward FFT +""" +helpUtiConvWithGaussian = """UtiConvWithGaussian(_data, _inMesh, _inSig) +function performs convolution of 1D or 2D data wave with 1D or 2D Gaussian (as defined by arguments) +:param _data: input / output float (single-precision) type array of data to be convolved with Gaussian; + in the case of a 2D convolution, the data should be "C-aligned" in 1D array, + with the first dimension being "inner" (i.e. most frequently changing); + the convolution is performed "in place", i.e. the input _data will be replaced by a resulting data +:param _inMesh: input list specifying (equidistant, regular) mesh of the data to be transformed: + _inMesh[0]: start value of the first argument + _inMesh[1]: step size value of the first argument + _inMesh[2]: number of points over the first argument + _inMesh[3]: (optional, to be used for 2D convolution) start value of the second argument + _inMesh[4]: (optional, to be used for 2D convolution) step size value of the second argument + _inMesh[5]: (optional, to be used for 2D convolution) number of points of the second argument + if len(_mesh) == 3, 1D convolution will be performed + else if len(_mesh) == 6, 2D convolution will be performed +:param _inSig: input list of central 2nd order statistical moments of 1D or 2D Gaussian, + and possibly a coefficient before cross-term: + _inSig[0]: RMS size of teh Gaussian in first dimension + _inSig[1]: (optional) RMS size of a 2D Gaussian in second dimension + _inSig[2]: (optional) coefficient before cross-term in exponent argument of a 2D Gaussian + i.e. _inSig[] = [sigX, sigY, alp} defines a "tilted" normalized 2D Gaussian (vs x, y): + (sqrt(1 - (alp*sigX*sigY)**2)/(2*Pi*sigX*sigY))*exp(-x**2/(2*sigX**2) - y**2/(2*sigY^2) - alp*x*y) +""" +helpUtiUndFromMagFldTab = """UtiUndFromMagFldTab(_undMagFldC, _inMagFldC, _inPrec) +function attempts to create periodic undulator structure from tabulated magnetic field +:param _undMagFldC: input / output magnetic field container structure (instance of SRWLMagFldC) with undulator structure + to be set up being allocated in _undMagFldC.arMagFld[0] +:param _inMagFldC: input magnetic field container structure with tabulated field structure to be analyzed; + the tabulated field structure (instance of SRWLMagFld3D) has to be defined in _inMagFldC.arMagFld[0] +:param _inPrec: input list of precision parameters: + _inPrec[0]: relative accuracy threshold (nominal value is 0.01) + _inPrec[1]: maximal number of magnetic field harmonics to attempt to create + _inPrec[2]: maximal magnetic period length to consider +""" diff --git a/env/release/srw_python/srwlib.pyc b/env/release/srw_python/srwlib.pyc deleted file mode 100644 index b1bc2550..00000000 Binary files a/env/release/srw_python/srwlib.pyc and /dev/null differ diff --git a/env/release/srw_python/srwlpy.pyd b/env/release/srw_python/srwlpy.pyd index 2c082f42..36c05bef 100644 Binary files a/env/release/srw_python/srwlpy.pyd and b/env/release/srw_python/srwlpy.pyd differ diff --git a/env/release/srw_python/srwlpy.so b/env/release/srw_python/srwlpy.so index 96d1cecb..2e06874e 100644 Binary files a/env/release/srw_python/srwlpy.so and b/env/release/srw_python/srwlpy.so differ diff --git a/env/release/srw_python/uti_io.py b/env/release/srw_python/uti_io.py new file mode 100644 index 00000000..e1926470 --- /dev/null +++ b/env/release/srw_python/uti_io.py @@ -0,0 +1,146 @@ +############################################################################# +# Basic Input/Output Utility Functions +# v 0.01 +############################################################################# + +#**********************Auxiliary function to write auxiliary/debugging information to an ASCII file: +def write_text(_text, _file_path): + f = open(_file_path, 'w') + f.write(_text + '\n') + f.close() + +#**********************Auxiliary function to read-in data comumns from ASCII file (2D table): +def read_ascii_data_cols(_file_path, _str_sep, _i_col_start=0, _i_col_end=-1, _n_line_skip=0): + """ + Auxiliary function to read-in data comumns from ASCII file (2D table) + :param _file_path: full path (including file name) to the file + :param _str_sep: column separation symbol(s) (string) + :param _i_col_start: initial data column to read + :param _i_col_end: final data column to read + :param _n_line_skip: number of lines to skip in the beginning of the file + :return: 2D list containing data columns read + """ + f = open(_file_path, 'r') + lines = f.readlines() + + resCols = [] + + #nCol = _i_col_end - _i_col_start + 1 + #for iCol in range(nCol): + # resCols.append([]) + + nRows = len(lines) - _n_line_skip + + for i in range(nRows): + curLine = lines[_n_line_skip + i] + curLineParts = curLine.split(_str_sep) + curNumParts = len(curLineParts) + #print(curLineParts) + + colCount = 0; colCountTrue = 0 + for iCol in range(curNumParts): + curPart = curLineParts[iCol] + #print(curPart) + + if(len(curPart) > 0): + if(((_i_col_start <= colCount) or (_i_col_start < 0)) and ((colCount <= _i_col_end) or (_i_col_end < 0))): + if len(resCols) < (colCountTrue + 1): resCols.append([]) + resCols[colCountTrue].append(float(curPart)) + colCountTrue += 1 + colCount += 1 + f.close() + return resCols #attn: returns lists, not arrays! + +#**********************Auxiliary function to write (save) data comumns to ASCII file (2D table): +def write_ascii_data_cols(_file_path, _cols, _str_sep, _str_head=None, _i_col_start=0, _i_col_end=-1): + """ + Auxiliary function to write tabulated data (columns, i.e 2D table) to ASCII file + :param _file_path: full path (including file name) to the file to be (over-)written + :param _cols: array of data columns to be saves to file + :param _str_sep: column separation symbol(s) (string) + :param _str_head: header (string) to write before data columns + :param _i_col_start: initial data column to write + :param _i_col_end: final data column to write + """ + f = open(_file_path, 'w') + + if(_str_head != None): + lenStrHead = len(_str_head) + if(lenStrHead > 0): + strHead = _str_head + if(_str_head[lenStrHead - 1] != '\n'): + strHead = copy(_str_head) + '\n' + f.write(strHead) + if(_cols == None): + f.close(); return + + nCols = len(_cols) + if(nCols <= 0): + f.close(); return + + nLines = len(_cols[0]) + for i in range(1, nCols): + newLen = len(_cols[i]) + if(nLines < newLen): nLines = newLen + + strSep = '\t' + if(_str_sep != None): + if(len(_str_sep) > 0): strSep = _str_sep + + strTot = '' + iColEndP1 = nCols + if((_i_col_end >= 0) and (_i_col_end < nCols)): iColEndP1 = _i_col_end + 1 + iColEnd = iColEndP1 - 1 + nLinesM1 = nLines - 1 + + for i in range(nLines): + curLine = '' + for j in range(_i_col_start, iColEndP1): + curElem = ' ' + if(i < len(_cols[j])): curElem = repr(_cols[j][i]) + curLine += curElem + if(j < iColEnd): curLine += strSep + if(i < nLinesM1): curLine += '\n' + strTot += curLine + + f.write(strTot) + f.close() + +#********************** Read data from an image file: +def read_image(image_path): # MR26102017 + """Read data from an image file. + + :param image_path: full path to the image. + :return: dict with the processed data. + """ + + msg = '{0} library is not installed. Use "pip install {0}" to install it.' + try: + import numpy as np + except: + raise ImportError(msg.format('numpy')) + try: + from PIL import Image + except: + raise ImportError(msg.format('pillow')) + + # Read the image: + raw_image = Image.open(image_path) + image_format = raw_image.format + raw_image = raw_image.convert('L') + + # Convert it to NumPy array: + data = np.array(raw_image) + if image_format not in ('TIFF', 'PNG', 'BMP', 'GIF', 'JPEG'): + raise ValueError('"{}" format is not supported at the moment.'.format(raw_image.format)) + + # Get bits per point: + mode_to_bpp = {'1': 1, 'L': 8, 'P': 8, 'I;16': 16, 'RGB': 24, 'RGBA': 32, 'CMYK': 32, 'YCbCr': 24, 'I': 32, 'F': 32} + bpp = mode_to_bpp[raw_image.mode] + limit_value = float(2 ** bpp - 1) + + return { + 'data': data, + 'raw_image': raw_image, + 'limit_value': limit_value, + } diff --git a/env/release/srw_python/uti_math.py b/env/release/srw_python/uti_math.py new file mode 100644 index 00000000..9a46268c --- /dev/null +++ b/env/release/srw_python/uti_math.py @@ -0,0 +1,685 @@ +############################################################################# +# uti_math module: misc. mathematical utilities / functions +# v 0.03 +# Authors: O.C., Maksim Rakitin +############################################################################# + +from __future__ import print_function #Python 2.7 compatibility +from array import * +from math import * +from copy import * +#import random +#import sys +#import os + +#**************************************************************************** +def interp_1d(_x, _x_min, _x_step, _nx, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): + """ + Interpolate 1D function value tabulated on equidistant mesh, using polynomial interpolation + :param _x: argument at which function value should be calculated + :param _x_min: minimal argument value of the tabulated function + :param _x_step: step of mesh at which function is tabulated + :param _nx: number of points in mesh at which function is tabulated + :param _ar_f: tabulated function list or array + :param _ord: order of polynomial interpolation (1- linear, 2- quadratic, 3- cubic) + :param _ix_per: argument index period of function data alignment (e.g. to interpolate one component of complex data, or in one dimension of multi-dimensional data) + :param _ix_ofst: argument index offset of function data alignment + :return: function value found by polynomial interpolation + """ + if(_ord == 1): + i0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) + if(i0 < 0): + i0 = 0 + elif(i0 >= _nx - 1): + i0 = _nx - 2 + i1 = i0 + 1 + f0 = _ar_f[i0*_ix_per + _ix_ofst] + f1 = _ar_f[i1*_ix_per + _ix_ofst] + t = (_x - (_x_min + _x_step*i0))/_x_step + return f0 + (f1 - f0)*t + elif(_ord == 2): + i0 = int(round((_x - _x_min)/_x_step)) + if(i0 < 1): + i0 = 1 + elif(i0 >= _nx - 1): + i0 = _nx - 2 + im1 = i0 - 1 + i1 = i0 + 1 + t = (_x - (_x_min + _x_step*i0))/_x_step + a0 = _ar_f[i0*_ix_per + _ix_ofst] + fm1 = _ar_f[im1*_ix_per + _ix_ofst] + f1 = _ar_f[i1*_ix_per + _ix_ofst] + a1 = 0.5*(f1 - fm1) + a2 = 0.5*(fm1 + f1 - 2*a0) + return a0 + t*(a1 + t*a2) + elif(_ord == 3): + i0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) + if(i0 < 1): + i0 = 1 + elif(i0 >= _nx - 2): + i0 = _nx - 3 + im1 = i0 - 1 + i1 = i0 + 1 + i2 = i0 + 2 + t = (_x - (_x_min + _x_step*i0))/_x_step + a0 = _ar_f[i0*_ix_per + _ix_ofst] + fm1 = _ar_f[im1*_ix_per + _ix_ofst] + f1 = _ar_f[i1*_ix_per + _ix_ofst] + f2 = _ar_f[i2*_ix_per + _ix_ofst] + a1 = -0.5*a0 + f1 - f2/6. - fm1/3. + a2 = -a0 + 0.5*(f1 + fm1) + a3 = 0.5*(a0 - f1) + (f2 - fm1)/6. + return a0 + t*(a1 + t*(a2 + t*a3)) + return 0 + +#**************************************************************************** +#def interp_1d_lin_var(_x, _ar_x, _ar_f): +def interp_1d_var(_x, _ar_x, _ar_f, _ord=3): + """ + Interpolate linearly 1D function value tabulated on non-equidistant (irregular) mesh + :param _x: argument at which function value should be calculated + :param _ar_x: array or list of increasing argument values, at which the function is tabulated + :param _ar_f: array or list of tabulated values corresponding to arguments in _ar_x + :param _ord: order of polynomial interpolation (1- linear, 2- quadratic, 3- cubic) + :return: function value found by polynomial interpolation + """ + + sErrBadArrays = 'Incorrect/incompatible lengths of argument and function value arrays.' + + nx = len(_ar_x) + if(nx <= 0): raise Exception(sErrBadArrays) + nf = len(_ar_f) + if(nf <= 0): raise Exception(sErrBadArrays) + + if(nx > nf): nx = nf + if(nx < 2): raise Exception(sErrBadArrays) + + nx_mi_1 = nx - 1 + + if(_x <= _ar_x[0]): return _ar_f[0] + elif(_x >= _ar_x[nx_mi_1]): return _ar_f[nx_mi_1] + + if(_ord > nx_mi_1): _ord = nx_mi_1 + + i0 = 0 + for i in range(1, nx): + if(_x < _ar_x[i]): + i0 = i - 1 + break + + if(_ord == 1): + #return interp_1d(_x, _ar_x[i0], _ar_x[i0+1] - _ar_x[i0], 2, [_ar_f[i0], _ar_f[i0+1]], 1) + x0 = _ar_x[i0] + step = _ar_x[i0+1] - x0 + t = (_x - x0)/step + f0 = _ar_f[i0] + return f0 + (_ar_f[i0+1] - f0)*t + + elif(_ord == 2): + im1 = i0 - 1 + ip1 = i0 + 1 + #nm1 = nx - 1 + if(ip1 < 0): + im1 = 0 + i0 = 1 + ip1 = 2 + elif(ip1 > nx_mi_1): + im1 = nx - 3 + i0 = nx - 2 + ip1 = nx_mi_1 + + xm1 = _ar_x[im1] + x0 = _ar_x[i0] + xp1 = _ar_x[ip1] + dxm1 = abs(_x - xm1) + dx0 = abs(_x - x0) + dxp1 = abs(_x - xp1) + if(dxm1 < dx0): + if(im1 > 0): + im1 -= 1 + i0 -= 1 + ip1 -= 1 + elif(dxp1 < dx0): + if(ip1 < nx_mi_1): + im1 += 1 + i0 += 1 + ip1 += 1 + + x0 = _ar_x[i0] + dxm1 = _ar_x[im1] - x0 + dxp1 = _ar_x[ip1] - x0 + fm1 = _ar_f[im1] + f0 = _ar_f[i0] + fp1 = _ar_f[ip1] + + invD = 1./(dxm1* dxp1*(dxm1 - dxp1)) + a = ((dxm1 - dxp1)*f0 + dxp1*fm1 - dxm1*fp1)*invD + b = (dxp1*dxp1*(f0 - fm1) + dxm1*dxm1*(fp1 - f0))*invD + dx = _x - x0 + return (a*dx + b)*dx + f0 + + elif(_ord == 3): + im1 = i0 - 1 + ip1 = i0 + 1 + ip2 = i0 + 2 + if(im1 < 0): + im1 = 0 + i0 = 1 + ip1 = 2 + ip2 = 3 + elif(ip2 > nx_mi_1): + im1 = nx - 4 + i0 = nx - 3 + ip1 = nx - 2 + ip2 = nx_mi_1 + + x0 = _ar_x[i0] + dxm1 = _ar_x[im1] - x0 + dxp1 = _ar_x[ip1] - x0 + dxp2 = _ar_x[ip2] - x0 + fm1 = _ar_f[im1] + f0 = _ar_f[i0] + fp1 = _ar_f[ip1] + fp2 = _ar_f[ip2] + #print(_x - x0, dxm1, dxp1, dxp2) + #print(fm1, f0, fp1, fp2) + + invD = 1./(dxm1*dxp1*dxp2*(dxm1 - dxp1)*(dxm1 - dxp2)*(dxp1 - dxp2)) + invD1 = 1./(dxm1*dxp1*dxp2) + dxm1e2 = dxm1*dxm1 + dxm1e3 = dxm1e2*dxm1 + dxp1e2 = dxp1*dxp1 + dxp1e3 = dxp1e2*dxp1 + dxp2e2 = dxp2*dxp2 + dxp2e3 = dxp2e2*dxp2 + a1 = (-dxp1e2*(dxp1 - dxp2)*dxp2e2*(f0 - fm1) + dxm1e2*(dxp2e3*(fp1 - f0) + dxp1e3*(f0 - fp2)) + dxm1e3*(dxp2e2*(f0 - fp1) + dxp1e2*(fp2 - f0)))*invD + a2 = ((dxm1 + dxp1 + dxp2)*f0)*invD1 + (dxm1*dxp2*(dxm1e2 - dxp2e2)*fp1 + dxp1e3*(dxm1*fp2 - dxp2*fm1) + dxp1*(dxp2e3*fm1 - dxm1e3*fp2))*invD + a3 = -f0*invD1 + (dxm1*dxp2*(dxp2 - dxm1)*fp1 + dxp1e2*(dxp2*fm1 - dxm1*fp2) + dxp1*(dxm1e2*fp2 - dxp2e2*fm1))*invD + dx = _x - x0 + return ((a3*dx + a2)*dx + a1)*dx + f0 + +#**************************************************************************** +def interp_2d(_x, _y, _x_min, _x_step, _nx, _y_min, _y_step, _ny, _ar_f, _ord=3, _ix_per=1, _ix_ofst=0): + """ + Interpolate 2D function value tabulated on equidistant rectangular mesh and represented by C-aligned flat array, using polynomial interpolation + :param _x: first argument at which function value should be calculated + :param _y: second argument at which function value should be calculated + :param _x_min: minimal value of the first argument of the tabulated function + :param _x_step: step of the first argument at which function is tabulated + :param _nx: number of points vs first argument at which function is tabulated + :param _y_min: minimal value of the second argument of the tabulated function + :param _y_step: step of the second argument at which function is tabulated + :param _ny: number of points vs second argument at which function is tabulated + :param _ar_f: function tabulated on 2D mesh, aligned as "flat" C-type list or array (first argument is changing most frequently) + :param _ord: "order" of polynomial interpolation (1- bi-linear (on 4 points), 2- "bi-quadratic" (on 6 points), 3- "bi-cubic" (on 12 points)) + :param _ix_per: period of first argument index of the function data alignment (e.g. to interpolate one component of complex data, or in one dimension of multi-dimensional data) + :param _ix_ofst: offset of the first argument index in function data alignment + :return: function value found by 2D polynomial interpolation + """ + if(_ord == 1): #bi-linear interpolation based on 4 points + ix0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) + if(ix0 < 0): + ix0 = 0 + elif(ix0 >= _nx - 1): + ix0 = _nx - 2 + ix1 = ix0 + 1 + tx = (_x - (_x_min + _x_step*ix0))/_x_step + + iy0 = int(trunc((_y - _y_min)/_y_step + 1.e-09)) + if(iy0 < 0): + iy0 = 0 + elif(iy0 >= _ny - 1): + iy0 = _ny - 2 + iy1 = iy0 + 1 + ty = (_y - (_y_min + _y_step*iy0))/_y_step + + nx_ix_per = _nx*_ix_per + iy0_nx_ix_per = iy0*nx_ix_per + iy1_nx_ix_per = iy1*nx_ix_per + ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst + ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst + a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] + f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] + f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] + f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] + a10 = f10 - a00 + a01 = f01 - a00 + a11 = a00 - f01 - f10 + f11 + return a00 + tx*(a10 + ty*a11) + ty*a01 + + elif(_ord == 2): #bi-quadratic interpolation based on 6 points + ix0 = int(round((_x - _x_min)/_x_step)) + if(ix0 < 1): + ix0 = 1 + elif(ix0 >= _nx - 1): + ix0 = _nx - 2 + ixm1 = ix0 - 1 + ix1 = ix0 + 1 + tx = (_x - (_x_min + _x_step*ix0))/_x_step + + iy0 = int(round((_y - _y_min)/_y_step)) + if(iy0 < 1): + iy0 = 1 + elif(iy0 >= _ny - 1): + iy0 = _ny - 2 + iym1 = iy0 - 1 + iy1 = iy0 + 1 + ty = (_y - (_y_min + _y_step*iy0))/_y_step + + nx_ix_per = _nx*_ix_per + iym1_nx_ix_per = iym1*nx_ix_per + iy0_nx_ix_per = iy0*nx_ix_per + iy1_nx_ix_per = iy1*nx_ix_per + ixm1_ix_per_p_ix_ofst = ixm1*_ix_per + _ix_ofst + ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst + ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst + fm10 = _ar_f[iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst] + a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] + f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] + f0m1 = _ar_f[iym1_nx_ix_per + ix0_ix_per_p_ix_ofst] + f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] + f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] + a10 = 0.5*(f10 - fm10) + a01 = 0.5*(f01 - f0m1) + a11 = a00 - f01 - f10 + f11 + a20 = 0.5*(f10 + fm10) - a00 + a02 = 0.5*(f01 + f0m1) - a00 + return a00 + tx*(a10 + tx*a20 + ty*a11) + ty*(a01 + ty*a02) + + elif(_ord == 3): #bi-cubic interpolation based on 12 points + ix0 = int(trunc((_x - _x_min)/_x_step + 1.e-09)) + if(ix0 < 1): + ix0 = 1 + elif(ix0 >= _nx - 2): + ix0 = _nx - 3 + ixm1 = ix0 - 1 + ix1 = ix0 + 1 + ix2 = ix0 + 2 + tx = (_x - (_x_min + _x_step*ix0))/_x_step + + iy0 = int(trunc((_y - _y_min)/_y_step + 1.e-09)) + if(iy0 < 1): + iy0 = 1 + elif(iy0 >= _ny - 2): + iy0 = _ny - 3 + iym1 = iy0 - 1 + iy1 = iy0 + 1 + iy2 = iy0 + 2 + ty = (_y - (_y_min + _y_step*iy0))/_y_step + + nx_ix_per = _nx*_ix_per + iym1_nx_ix_per = iym1*nx_ix_per + iy0_nx_ix_per = iy0*nx_ix_per + iy1_nx_ix_per = iy1*nx_ix_per + iy2_nx_ix_per = iy2*nx_ix_per + ixm1_ix_per_p_ix_ofst = ixm1*_ix_per + _ix_ofst + ix0_ix_per_p_ix_ofst = ix0*_ix_per + _ix_ofst + ix1_ix_per_p_ix_ofst = ix1*_ix_per + _ix_ofst + ix2_ix_per_p_ix_ofst = ix2*_ix_per + _ix_ofst + f0m1 = _ar_f[iym1_nx_ix_per + ix0_ix_per_p_ix_ofst] + f1m1 = _ar_f[iym1_nx_ix_per + ix1_ix_per_p_ix_ofst] + fm10 = _ar_f[iy0_nx_ix_per + ixm1_ix_per_p_ix_ofst] + a00 = _ar_f[iy0_nx_ix_per + ix0_ix_per_p_ix_ofst] + f10 = _ar_f[iy0_nx_ix_per + ix1_ix_per_p_ix_ofst] + f20 = _ar_f[iy0_nx_ix_per + ix2_ix_per_p_ix_ofst] + fm11 = _ar_f[iy1_nx_ix_per + ixm1_ix_per_p_ix_ofst] + f01 = _ar_f[iy1_nx_ix_per + ix0_ix_per_p_ix_ofst] + f11 = _ar_f[iy1_nx_ix_per + ix1_ix_per_p_ix_ofst] + f21 = _ar_f[iy1_nx_ix_per + ix2_ix_per_p_ix_ofst] + f02 = _ar_f[iy2_nx_ix_per + ix0_ix_per_p_ix_ofst] + f12 = _ar_f[iy2_nx_ix_per + ix1_ix_per_p_ix_ofst] + a10 = -0.5*a00 + f10 - f20/6 - fm10/3 + a01 = -0.5*a00 + f01 - f02/6 - f0m1/3 + a11 = -0.5*(f01 + f10) + (f02 - f12 + f20 - f21)/6 + (f0m1 - f1m1 + fm10 - fm11)/3 + f11 + a20 = -a00 + 0.5*(f10 + fm10) + a02 = -a00 + 0.5*(f01 + f0m1) + a21 = a00 - f01 + 0.5*(f11 - f10 - fm10 + fm11) + a12 = a00 - f10 + 0.5*(f11 - f01 - f0m1 + f1m1) + a30 = 0.5*(a00 - f10) + (f20 - fm10)/6 + a03 = 0.5*(a00 - f01) + (f02 - f0m1)/6 + a31 = 0.5*(f01 + f10 - f11 - a00) + (f21 + fm10 - f20 - fm11)/6 + a13 = 0.5*(f10 - f11 - a00 + f01) + (f0m1 + f12 - f02 - f1m1)/6 + return a00 + tx*(a10 + tx*(a20 + tx*(a30 + ty*a31) + ty*a21) + ty*a11) + ty*(a01 + ty*(a02 + ty*(a03 + tx*a13) + tx*a12)) + return 0 + +#**************************************************************************** +def num_round(_x, _ndig=8): +## if(_x == 0.): return _x +## sgn = 1. +## if(_x < 0.): +## _x = -_x +## sgn = -1 +## order = round(log10(_x)) +## fact = 10**order +## roundNum = round(_x/fact, _ndig) +## res = roundNum*fact*sgn + res = round(_x, _ndig) + return res + +#**************************************************************************** +def find_ar_max(_ar, _ib=0, _ie=-1, _min=False): + """ + Finds array (or list) maximum (or minimum), index and value + :param _ar: array (or list) to find max. or min. + :param _ib: array index to start search + :param _ie: array index to finish search + :param _min: switch specifying that minimum (rather than maximum) has to be searched + """ + + strErIncorArray = 'Incorrect input array.' + + if(_ar is None): raise Exception(strErIncorArray) + nTot = len(_ar) + if(nTot <= 0): raise Exception(strErIncorArray) + + iBeg = _ib + if(_ib < 0): iBeg = 0 + + iEnd = _ie + if((iEnd == -1) or (_ie >= nTot)): iEnd = nTot - 1 + + if(iEnd < iBeg): raise Exception('Incorrect definition of start and end indexes.') + + curExtr = _ar[0] + curInd = 0 + for i in range(iBeg, iEnd + 1, 1): + curVal = _ar[i] + if(_min == True): curVal *= -1 + if(curExtr < curVal): + curExtr = curVal + curInd = i + + return curExtr, curInd + +#**************************************************************************** +def integ_array(_ar, _h, _dupl=False): + """ + Integrates array (or list), eventually making a copy of it before the integration + :param _ar: array to integrate + :param _h: step size + :param _dupl: duplicate the magnetic field object or not + """ + ar = None + if(_dupl): ar = deepcopy(_ar) + else: ar = _ar + + hd2 = 0.5*_h + auxInt = 0 + lenAr = len(_ar) + for i in range(lenAr - 1): + ar_i = _ar[i] #in case if array has to be integrated in place + ar[i] = auxInt + auxInt += hd2*(ar_i + _ar[i + 1]) + ar[lenAr - 1] = auxInt + return ar + +#**************************************************************************** +def integ_ar_2d(_ar, _ar_align, _x_grid, _y_grid, _x_lim=None, _y_lim=None): + """ + Integrates 2d array (or list) within given limits + :param _ar: input array to integrate + :param _ar_align: input array alignment (1- _ar is C-type alignment, 2- _ar is 2d array) + :param _x_grid: list/array specifying grid vs one dimensions (_x_grid[0] is start, _x_grid[1] is end, _x_grid[2] is number of points) + :param _y_grid: list/array specifying grid vs another dimensions (_y_grid[0] is start, _y_grid[1] is end, _y_grid[2] is number of points) + :param _x_lim: list/array specifying inegration limits vs one dimensions (_x_lim[0] is start, _x_lim[1] is end) + :param _y_lim: list/array specifying inegration limits vs another dimensions (_y_lim[0] is start, _y_lim[1] is end) + """ + + if(_x_lim is not None): + #print(_x_lim[0], _x_lim[1]) + if(_x_lim[0] >= _x_lim[1]): return 0. + + if(_y_lim is not None): + #print(_y_lim[0], _y_lim[1]) + if(_y_lim[0] >= _y_lim[1]): return 0. + + #print(_x_grid); print(_x_lim) + #print(_y_grid); print(_y_lim) + + xStart = _x_grid[0]; xEnd = _x_grid[1]; nx = _x_grid[2] + xStep = (xEnd - xStart)/(nx - 1) + yStart = _y_grid[0]; yEnd = _y_grid[1]; ny = _y_grid[2] + yStep = (yEnd - yStart)/(ny - 1) + + if((xStep == 0) or (yStep == 0)): return 0. + + x_min = xStart; x_max = xEnd; nxInteg = 0 + if(_x_lim is not None): + x_min = _x_lim[0] + x_max = _x_lim[1] + if(len(_x_lim) > 2): nxInteg = int(round(_x_lim[2])) + + y_min = yStart; y_max = yEnd; nyInteg = 0 + if(_y_lim is not None): + y_min = _y_lim[0] + y_max = _y_lim[1] + if(len(_y_lim) > 2): nyInteg = int(round(_y_lim[2])) + + if((nxInteg > 2) and (nyInteg > 2) and (_ar_align == 1)): #perform inregration using 2D interpolation + + arAuxIntegWave2Dx = array('d', [0]*nxInteg) + if(x_min < xStart): x_min = xStart + if(x_max > xEnd): x_max = xEnd + xStepInteg = (x_max - x_min)/(nxInteg - 1) + + arAuxIntegWave2Dy = array('d', [0]*nyInteg) + if(y_min < yStart): y_min = yStart + if(y_max > yEnd): y_max = yEnd + yStepInteg = (y_max - y_min)/(nyInteg - 1) + + yy = y_min + for iy in range(nyInteg): + xx = x_min + for ix in range(nxInteg): + arAuxIntegWave2Dx[ix] = interp_2d(xx, yy, xStart, xStep, nx, yStart, yStep, ny, _ar, _ord=2) + xx += xStepInteg + + arAux = integ_array(arAuxIntegWave2Dx, xStepInteg) + arAuxIntegWave2Dy[iy] = arAux[nxInteg - 1] + yy += yStepInteg + + arAux = integ_array(arAuxIntegWave2Dy, yStepInteg) + resInteg = arAux[nyInteg - 1] + return resInteg + + ixStart = int((x_min - xStart)/xStep + 0.e-12) + if(ixStart < 0): ixStart = 0 + else: + if(ixStart >= nx): ixStart = nx - 1 + #print('ixStart=', ixStart) + + iyStart = int((y_min - yStart)/yStep + 0.e-12) + if(iyStart < 0): iyStart = 0 + else: + if(iyStart >= ny): iyStart = ny - 1 + #print('iyStart=', iyStart) + + ixEnd = int((x_max - xStart)/xStep - 1.e-06) + 1 + if(ixEnd < 0): ixEnd = 0 + else: + if(ixEnd >= nx): ixEnd = nx - 1 + #print('ixStart=', ixStart, 'ixEnd=', ixEnd) + + iyEnd = int((y_max - yStart)/yStep - 1.e-06) + 1 + if(iyEnd < 0): iyEnd = 0 + else: + if(iyEnd >= ny): iyEnd = ny - 1 + #print('iyStart=', iyStart, 'iyEnd=', iyEnd) + + if((ixStart >= ixEnd) or (iyStart >= iyEnd)): return 0. + + nxi = ixEnd - ixStart + 1 + ##make/O/N=(nxi) wAuxIntegWave2Dx + ##SetScale/P x, xStart + ixStart*xStep, xStep, "", wAuxIntegWave2Dx + arAuxIntegWave2Dx = array('d', [0]*nxi) + + nyi = iyEnd - iyStart + 1 + ##make/O/N=(nyi) wAuxIntegWave2Dy + ##SetScale/P x, yStart + iyStart*yStep, yStep, "", wAuxIntegWave2Dy + arAuxIntegWave2Dy = array('d', [0]*nyi) + + ##for(iy = 0; iy < nyi; iy += 1) + ## wAuxIntegWave2Dx = w2d[ixStart + p][iyStart + iy] + ## integrate/T wAuxIntegWave2Dx + ## wAuxIntegWave2Dy[iy] = wAuxIntegWave2Dx(x_max) - wAuxIntegWave2Dx(x_min) + ##endfor + + iyAbs_nx = 0 + ar_iyAbs = None + for iy in range(nyi): + iyAbs = iy + iyStart + if(_ar_align == 1): iyAbs_nx = iyAbs*nx + else: ar_iyAbs = _ar[iyAbs] + + for ix in range(nxi): + ixAbs = ix + ixStart + if(_ar_align == 1): arAuxIntegWave2Dx[ix] = _ar[iyAbs_nx + ixAbs] + else: arAuxIntegWave2Dx[ix] = ar_iyAbs[ixAbs] + + #print(xStep, arAuxIntegWave2Dx) + arAux = integ_array(arAuxIntegWave2Dx, xStep) + arAuxIntegWave2Dy[iy] = arAux[nxi - 1] + + ##integrate/T wAuxIntegWave2Dy + ##variable res = wAuxIntegWave2Dy(y_max) - wAuxIntegWave2Dy(y_min) + + arAux = integ_array(arAuxIntegWave2Dy, yStep) + resInteg = arAux[nyi - 1] + return resInteg + +#**************************************************************************** +def matr_prod(_A, _B): + """ + Multiplies matrix _A by matrix _B + """ + # Matrix multiplication + B0 = _B[0] + lenB = len(_B) + lenA = len(_A) + if(len(_A[0]) != lenB): # Check matrix dimensions + Exception('Matrices have wrong dimensions') + if(isinstance(B0, list) or isinstance(B0, array) or isinstance(B0, tuple)): #_B is matrix + lenB0 = len(B0) + C = [[0 for row in range(lenB0)] for col in range(lenA)] + for i in range(lenA): + for j in range(lenB0): + for k in range(lenB): + C[i][j] += _A[i][k]*_B[k][j] + else: #_B is vector + C = [0 for row in range(lenB)] + for i in range(lenA): + for k in range(lenB): + C[i] += _A[i][k]*_B[k] + return C + +#**************************************************************************** +def matr_print(_A): + """ + Prints matrix _A + """ + for i in range(len(_A)): + print(_A[i]) + +#**************************************************************************** +def matr_3x3_det(_M): + S0 = _M[0]; S1 = _M[1]; S2 = _M[2] + return S0[0]*S1[1]*S2[2] + S0[1]*S1[2]*S2[0] + S0[2]*S1[0]*S2[1] - S0[2]*S1[1]*S2[0] - S0[0]*S1[2]*S2[1] - S0[1]*S1[0]*S2[2] + +#**************************************************************************** +def matr_3x3_inv(_M): + S0 = _M[0]; S1 = _M[1]; S2 = _M[2] + invDet = 1./(S0[0]*S1[1]*S2[2] + S0[1]*S1[2]*S2[0] + S0[2]*S1[0]*S2[1] - S0[2]*S1[1]*S2[0] - S0[0]*S1[2]*S2[1] - S0[1]*S1[0]*S2[2]) + S0i = [invDet*(S1[1]*S2[2] - S1[2]*S2[1]), invDet*(-S0[1]*S2[2] + S0[2]*S2[1]), invDet*(S0[1]*S1[2] - S0[2]*S1[1])] + S1i = [invDet*(-S1[0]*S2[2] + S1[2]*S2[0]), invDet*(S0[0]*S2[2] - S0[2]*S2[0]), invDet*(-S0[0]*S1[2] + S0[2]*S1[0])] + S2i = [invDet*(S1[0]*S2[1] - S1[1]*S2[0]), invDet*(-S0[0]*S2[1] + S0[1]*S2[0]), invDet*(S0[0]*S1[1] - S0[1]*S1[0])] + return [S0i, S1i, S2i] + +#**************************************************************************** +def trf_rotation(_V, _ang, _P): + """ + Sets up matrix and vector describing rotation about axis _V passing through a point _P about an angle _ang + :param _V: vector (array of 3 Cartesian coordinates) defining rotation axis + :param _ang: rotation angle [rad] + :param _P: point (array of 3 Cartesian coordinates) rotation axis passes through + :returns list containing the 3x3 matrix and 3-element vector + """ + normFact = 1./sqrt(_V[0]*_V[0] + _V[1]*_V[1] + _V[2]*_V[2]) + axVect = [normFact*_V[0], normFact*_V[1], normFact*_V[2]] + VxVx = axVect[0]*axVect[0] + VyVy = axVect[1]*axVect[1] + VzVz = axVect[2]*axVect[2] + cosAng = cos(_ang) + sinAng = sin(_ang) + one_m_cos = 1. - cosAng + one_m_cosVxVy = one_m_cos*axVect[0]*axVect[1] + one_m_cosVxVz = one_m_cos*axVect[0]*axVect[2] + one_m_cosVyVz = one_m_cos*axVect[1]*axVect[2] + sinVx = sinAng*axVect[0] + sinVy = sinAng*axVect[1] + sinVz = sinAng*axVect[2] + st0 = [VxVx + cosAng*(VyVy + VzVz), one_m_cosVxVy - sinVz, one_m_cosVxVz + sinVy] + st1 = [one_m_cosVxVy + sinVz, VyVy + cosAng*(VxVx + VzVz), one_m_cosVyVz - sinVx] + st2 = [one_m_cosVxVz - sinVy, one_m_cosVyVz + sinVx, VzVz + cosAng*(VxVx + VyVy)] + M = [st0, st1, st2] + st00 = [1. - st0[0], -st0[1], -st0[2]] + st01 = [-st1[0], 1. - st1[1], -st1[2]] + st02 = [-st2[0], -st2[0], 1. - st2[2]] + M0 = [st00, st01, st02] + V = matr_prod(M0, _P) + return [M, V] + +#**************************************************************************** +def fwhm(x, y, shift=0.5, return_as_dict=False): # MR21032017 + """The function searches x-values (roots) where y=0 (after normalization to values between 0 and 1 and shifting the + values down by 0.5 (default value)) based on linear interpolation, and calculates full width at half maximum (FWHM). + + :param x: an array of x values. + :param y: an array of y values. + :param shift: an optional shift to be used in the process of normalization (between 0 and 1). + :param return_as_dict: if to return a dict with 'fwhm' and 'x_range' + :return: a value of the FWHM or dictionary consisting of 'fwhm' and 'x_range' + """ + + def is_positive(num): + return True if num > 0 else False + + # Normalize values first: + #y = (y - min(y)) / (max(y) - min(y)) - shift # roots are at Y=0 + + #OC18112017 (making it work with standard Python lists / arrays) + minY = min(y) + maxY = max(y) + if(maxY == minY): raise Exception('FWHM can not be calculated') + mult = 1./(maxY - minY) + lenY = len(y) + for i in range(lenY): y[i] = (y[i] - minY)*mult - shift + + positive = is_positive(y[0]) + list_of_roots = [] + #for i in range(len(y)): + for i in range(lenY): + current_positive = is_positive(y[i]) + if current_positive != positive: + list_of_roots.append(x[i - 1] + (x[i] - x[i - 1]) / (abs(y[i]) + abs(y[i - 1])) * abs(y[i - 1])) + positive = not positive + if len(list_of_roots) >= 2: + if not return_as_dict: + return abs(list_of_roots[-1] - list_of_roots[0]) + else: + return { + 'fwhm': abs(list_of_roots[-1] - list_of_roots[0]), + 'x_range': list_of_roots, + } + else: + raise Exception('Number of roots is less than 2!') + +#**************************************************************************** +#def fwhm_scipy(x, y): #MR27092016 +# """Computing FWHM (Full width at half maximum)""" +# try: +# from scipy.interpolate import UnivariateSpline +# spline = UnivariateSpline(x, y, s=0) +# r1, r2 = spline.roots() # find the roots +# return r2 - r1 # return the difference (full width) +# except ImportError: +# return fwhm(x, y) diff --git a/env/release/srw_python/uti_parse.py b/env/release/srw_python/uti_parse.py new file mode 100644 index 00000000..be454230 --- /dev/null +++ b/env/release/srw_python/uti_parse.py @@ -0,0 +1,45 @@ +############################################################################# +# Basic String / Array / List Parsing Utility Functions +# v 0.01 +############################################################################# + +#**********************Convert two strings with separators to a list of pairs +def str_to_list_of_pairs(_str1, _str2, _sep=','): + """ + Attempts to convert 2 strings containing tokens separated by some _sep to a list of pairs, e.g. "a1,a2", "b1,b2" -> [['a1','b1'],['a2','b2']] + :param _str1: input string #1 + :param _str2: input string #2 + :param _sep: token separator in the strings + :returns: list of pairs of the corresponding tokens + """ + + if((_str1 is None) or (_str2 is None) or (_str1 == '') or (_str2 == '')): return None + + lstTok1 = _str1.split(_sep) + numTok1 = len(lstTok1) + lstTok2 = _str2.split(_sep) + numTok2 = len(lstTok2) + numTok = numTok1 if(numTok1 <= numTok2) else numTok2 + + lstRes = [] + for i in range(numTok): + lstRes.append([lstTok1[i], lstTok2[i]]) + + return lstRes + +#**********************Convert two strings with separators to a list of pairs +def str_to_pair_of_lists(_str1, _str2, _sep=','): + """ + Attempts to convert 2 strings containing tokens separated by some _sep to a pair of lists, e.g. "a1,a2,a3", "b1,b2,b3" -> [['a1','a2','a3'],['b1','b2','b3']] + :param _str1: input string #1 + :param _str2: input string #2 + :param _sep: token separator in the strings + :returns: list of pairs of the corresponding tokens + """ + + if((_str1 is None) or (_str2 is None) or (_str1 == '') or (_str2 == '')): return None + + lstTok1 = _str1.split(_sep) + lstTok2 = _str2.split(_sep) + + return [lstTok1, lstTok2] diff --git a/env/release/srw_python/uti_plot.py b/env/release/srw_python/uti_plot.py new file mode 100644 index 00000000..ac6f27c4 --- /dev/null +++ b/env/release/srw_python/uti_plot.py @@ -0,0 +1,234 @@ +"""Simple 1D & 2D plotting utilities package for "Synchrotron Radiation Workshop" (SRW). + +``uti_plot`` currently wraps ``matplotlib``, but other backends are +planned. If no suitable backend is available, ``uti_plot_init`` sets +the backend to ``uti_plot_none`` so that the calling program is still +functional. This is useful for systems where there is no graphing +library available, but you still want to see the results of the +SRW program. + +Usage: + + import uti_plot as up + + up.uti_plot_init() + uti_plot1d(...) + uti_plot_show() + +Modules: + + uti_plot + This module, which loads all other modules dynamically + + uti_plot_matplotlib + Does the actually plotting using matplotlib.pyplot. Currently, loaded in all cases except + when ``backend`` is ``None`` + + test_uti_plot + Simple tests for uti_plot + +.. moduleauthor:: Rob Nagler +""" +import sys +import uti_plot_com +import traceback + +_backend = None + +DEFAULT_BACKEND = '' + +def uti_plot_init(backend=DEFAULT_BACKEND, fname_format=None): + """Initializes plotting engine with backend and, optionally, save plots to fname_format + + Tries to initialize `backend` as the plotting engine. If not found, an + error will be printed, and this module's functions will be no-ops. If + DEFAULT_BACKEND provided, an appropriate backend will be chosen and printed. + Plots may also be saved if fname_format is supplied. + + You may call ``uti_plot_init(None)`` explicitly so that no plotting occurs. + + :param str backend: a matplot backend (TkAgg, etc.) or ``inline`` in IPython + :param str fname_format: where to save plots. format field is a sequential plot number, starting at 0. + """ + global _backend + if backend is not None: + try: + import uti_plot_matplotlib + _backend = uti_plot_matplotlib.Backend(backend, fname_format) + return + except: + traceback.print_exc() + print(backend + ': unable to import specified backend (or its dependency); no plots') + elif fname_format is not None: + #raise Value(fname_format + ': fname_format must be null if backend is None') + raise ValueError(fname_format + ': fname_format must be null if backend is None') + _backend = _BackendNone() + +def uti_plot_show(): + """Display the plots""" + #if '_backend' not in locals(): uti_plot_init() #? + _backend.uti_plot_show() + +def uti_plot1d(ar1d, x_range, labels=('Photon Energy [eV]', 'ph/s/0.1%bw'), units=None): + """Generate one-dimensional line plot from given array + + :param array ar1d: data points + :param list x_range: Passed to numpy.linspace(start sequence, stop sequnce, num samples) + :param tuple labels: [x-axis, y-axis] + """ + #if '_backend' not in locals(): uti_plot_init() #? + + if(units is not None): + x_range, x_unit = uti_plot_com.rescale_dim(x_range, units[0]) + units = [x_unit, units[1]] + strTitle = '' if(len(labels) < 3) else labels[2] + labels = (labels[0] + ' [' + units[0] + ']', labels[1] + ' [' + units[1] + ']', strTitle) + + _backend.uti_plot1d(ar1d, x_range, labels) + +def uti_plot1d_ir(ary, arx, labels=('Longitudinal Position [m]', 'Horizontal Position [m]'), units=None): #OC15112017 + """Generate one-dimensional line plot from given array + + :param array arx: abscissa array + :param array ary: ordinate array + :param tuple labels: [x-axis, y-axis] + """ + #if '_backend' not in locals(): uti_plot_init() #? + + if(units is not None): + #x_range = [min(arx), max(arx), len(arx)] + #x_range, x_unit = uti_plot_com.rescale_dim(x_range, units[0]) + #units = [x_unit, units[1]] + strTitle = '' if(len(labels) < 3) else labels[2] + labels = (labels[0] + ' [' + units[0] + ']', labels[1] + ' [' + units[1] + ']', strTitle) + + _backend.uti_plot1d_ir(ary, arx, labels) + +def uti_plot2d(ar2d, x_range, y_range, labels=('Horizontal Position [m]','Vertical Position [m]'), units=None): + """Generate quad mesh plot from given "flattened" array + + :param array ar2d: data points + :param list x_range: Passed to numpy.linspace(start sequence, stop sequnce, num samples) + :param list y_range: y axis (same structure as x_range) + :param tuple labels: [x-axis, y-axis] + """ + #if '_backend' not in locals(): uti_plot_init() #? + if(units is not None): + x_range, x_unit = uti_plot_com.rescale_dim(x_range, units[0]) + y_range, y_unit = uti_plot_com.rescale_dim(y_range, units[1]) + units = [x_unit, y_unit, units[2]] + strTitle = '' if(len(labels) < 3) else labels[2] + labels = (labels[0] + ' [' + units[0]+ ']', labels[1] + ' [' + units[1] + ']', strTitle) + + _backend.uti_plot2d(ar2d, x_range, y_range, labels) + +def uti_plot2d1d(ar2d, x_range, y_range, x=0, y=0, labels=('Horizontal Position', 'Vertical Position', 'Intensity'), units=None, graphs_joined=True): + """Generate 2d quad mesh plot from given "flattened" array, and 1d cuts passing through (x, y) + + :param array ar2d: data points + :param list x_range: Passed to numpy.linspace(start sequence, stop sequnce, num samples) + :param list y_range: y axis (same structure as x_range) + :param x: x value for 1d cut + :param y: y value for 1d cut + :param tuple labels: [x-axis, y-axis, z-axis] + :param tuple units: [x-axis, y-axis, z-axis] + :param graphs_joined: switch specifying whether the 2d plot and 1d cuts have to be displayed in one panel or separately + """ + #if '_backend' not in locals(): uti_plot_init() #? + if(units is not None): #checking / re-scaling x, y + x_range, x_unit = uti_plot_com.rescale_dim(x_range, units[0]) + y_range, y_unit = uti_plot_com.rescale_dim(y_range, units[1]) + units = [x_unit, y_unit, units[2]] + + strTitle = labels[2] + label2D = (labels[0] + ' [' + units[0]+ ']', labels[1] + ' [' + units[1] + ']', strTitle) + + strTitle = 'At ' + labels[1] + ': ' + str(y) + if y != 0: strTitle += ' ' + units[1] + label1X = (labels[0] + ' [' + units[0] + ']', labels[2] + ' [' + units[2] + ']', strTitle) + + strTitle = 'At ' + labels[0] + ': ' + str(x) + if x != 0: strTitle += ' ' + units[0] + label1Y = (labels[1] + ' [' + units[1] + ']', labels[2] + ' [' + units[2] + ']', strTitle) + + else: #OC081115 + strTitle = labels[2] + label2D = (labels[0], labels[1], strTitle) + + strTitle = 'At ' + labels[1] + ': ' + str(y) + label1X = (labels[0], labels[2], strTitle) + + strTitle = 'At ' + labels[0] + ': ' + str(x) + label1Y = (labels[1], labels[2], strTitle) + + labels = [label2D, label1X, label1Y] + + _backend.uti_plot2d1d(ar2d, x_range, y_range, x, y, labels, graphs_joined) + +def uti_plot_data_file(_fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=True, #Same as uti_data_file_plot, but better fits function name decoration rules in this module (uti_plot*) + _multicolumn_data=False, _column_x=None, _column_y=None, #MR31102017 + _scale='linear', _width_pixels=None): + """Generate plot from configuration in _fname + + :param str _fname: config loaded from here + :param bool _read_labels: whether to read labels from _fname + :param float _e: photon energy adjustment + :param float _x: horizonal position adjustment + :param float _y: vertical position adjustment + :param bool _graphs_joined: if true, all plots in a single figure + :param bool _multicolumn_data: if true, visualize multicolumn data data + :param str _column_x: column for horizontal axis + :param str _column_x: column for vertical axis + :param str _scale: the scale to use for plotting data (linear by default, but could use log, log2, log10) + :param int _width_pixels: the width of the final plot in pixels + """ + #if '_backend' not in locals(): uti_plot_init() #? + _backend.uti_plot_data_file(_fname, _read_labels, _e, _x, _y, _graphs_joined, + _multicolumn_data, _column_x, _column_y, #MR31102017 + _scale, _width_pixels) + +#def uti_data_file_plot(_fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=True): +#def uti_data_file_plot(_fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=True, _traj_report=False, _traj_axis='x'): #MR29072016 +#def uti_data_file_plot(_fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=True, _traj_report=False, _traj_axis='x', _scale='linear', _width_pixels=None): #MR20012017 +def uti_data_file_plot(_fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=True, + _multicolumn_data=False, _column_x=None, _column_y=None, #MR31102017 + _scale='linear', _width_pixels=None): + """Generate plot from configuration in _fname + + :param str _fname: config loaded from here + :param bool _read_labels: whether to read labels from _fname + :param float _e: photon energy adjustment + :param float _x: horizonal position adjustment + :param float _y: vertical position adjustment + :param bool _graphs_joined: if true, all plots in a single figure + :param bool _multicolumn_data: if true, visualize multicolumn data data + :param str _column_x: column for horizontal axis + :param str _column_x: column for vertical axis + :param str _scale: the scale to use for plotting data (linear by default, but could use log, log2, log10) + :param int _width_pixels: the width of the final plot in pixels + """ + #if '_backend' not in locals(): uti_plot_init() #? + #_backend.uti_data_file_plot(_fname, _read_labels, _e, _x, _y, _graphs_joined) + #_backend.uti_data_file_plot(_fname, _read_labels, _e, _x, _y, _graphs_joined, _traj_report, _traj_axis) #MR29072016 + #_backend.uti_data_file_plot(_fname, _read_labels, _e, _x, _y, _graphs_joined, _traj_report, _traj_axis, _scale, _width_pixels) #MR20012017 + #_backend.uti_data_file_plot(_fname, _read_labels, _e, _x, _y, _graphs_joined, + # _multicolumn_data, _column_x, _column_y, #MR31102017 + # _scale, _width_pixels) + uti_plot_data_file(_fname, _read_labels, _e, _x, _y, _graphs_joined, _multicolumn_data, _column_x, _column_y, _scale, _width_pixels) #OC16112017 + +class _BackendBase(object): + def __getattr__(self, attr): + return self._backend_call + +class _BackendMissing(_BackendBase): + def _backend_call(self, *args, **kwargs): + uti_plot_init() + method_name = sys._getframe(1).f_code.co_name + func = getattr(_backend, method_name) + return func(*args) + +class _BackendNone(_BackendBase): + def _backend_call(*args, **kwargs): + pass + +_backend = _BackendMissing() diff --git a/env/release/srw_python/uti_plot_com.py b/env/release/srw_python/uti_plot_com.py new file mode 100644 index 00000000..4b89d6d8 --- /dev/null +++ b/env/release/srw_python/uti_plot_com.py @@ -0,0 +1,250 @@ +"""uti_plot_com module containing plot utilities not specific to a particular backend + +.. moduleauthor:: +""" +from copy import * +from array import * +import traceback +#import sys +#import numpy as np + +import uti_math +import uti_io + +#**************************************************************************** +def _multicolumn_file_load(fname): #MR31102017 + with open(fname, 'r') as f: + header = f.readline().split(',') + header = [x.replace('#', '').strip() for x in header] + data = uti_io.read_ascii_data_cols(fname, '\t', _i_col_start=0, _i_col_end=-1, _n_line_skip=1) + d = {} + for i, k in enumerate(header): + k_no_units = k.split('[')[0].strip() + units = k.split('[')[1].split(']')[0].strip() + d[k_no_units] = { + 'data': data[i], + 'label': k, + 'units': units, + } + # data, mode, allrange, arLabels, arUnits + return d, None, [], [], [] + +#**************************************************************************** +#OBSOLETE +def _traj_file_load(fname, traj_axis='x'): #MR20160725 + nLinesHead = 1 + hlp = [] + with open(fname, 'r') as f: + for i in range(nLinesHead): + hlp.append(f.readline()) + + data = uti_io.read_ascii_data_cols(fname, '\t', _i_col_start=0, _i_col_end=10, _n_line_skip=nLinesHead) + + mode = 3 + allrange = [ + data[5][0], # z-coordinate begin + data[5][-1], # z-coordinate end + len(data[0]), # number of points + min(data[1]), # x-coordinate begin + max(data[1]), # x-coordinate end + 1, + min(data[3]), # y-coordinate begin + max(data[3]), # y-coordinate end + 1, + ] + arLabels = ['Longitudinal Position', 'Horizontal Position', 'Vertical Position'] + arUnits = ['m', 'm', 'm', 'm'] + if traj_axis == 'x': + data = data[1] + arLabels.append('Horizontal Coordinate') + elif traj_axis == 'y': + data = data[3] + arLabels.append('Vertical Coordinate') + else: + raise ValueError('Parameter "axis" has wrong value: {}. Allowed values are "x" and "y"'.format(traj_axis)) + + return data, mode, allrange, arLabels, arUnits + +#**************************************************************************** +#def srw_ascii_load(fname): +#def file_load(_fname, _read_labels=1): +def _file_load(_fname, _read_labels=1): #MR20160725 + nLinesHead = 11 + hlp = [] + #with open(_fname,'r') as f: hlp = f.readlines(nLinesHead) + with open(_fname,'r') as f: + for i in range(nLinesHead): + hlp.append(f.readline()) + + #ne, nx, ny, ns = [ int(hlp[i].replace('#','').split()[0]) for i in [3,6,9,10] ] + ne, nx, ny = [int(hlp[i].replace('#','').split()[0]) for i in [3,6,9]] + ns = 1 + testStr = hlp[nLinesHead - 1] + if testStr[0] == '#': + ns = int(testStr.replace('#','').split()[0]) + else: nLinesHead -= 1 + + e0,e1,x0,x1,y0,y1 = [float(hlp[i].replace('#','').split()[0]) for i in [1,2,4,5,7,8]] + + #data = np.squeeze(np.loadtxt(_fname, dtype=np.float64)) #get data from file (C-aligned flat) + data = uti_io.read_ascii_data_cols(_fname, '\t', _i_col_start=0, _i_col_end=0, _n_line_skip=nLinesHead)[0] + + allrange = e0, e1, ne, x0, x1, nx, y0, y1, ny + + arLabels = ['Photon Energy', 'Horizontal Position', 'Vertical Position', 'Intensity'] + arUnits = ['eV', 'm', 'm', 'ph/s/.1%bw/mm^2'] + + if _read_labels: + + arTokens = hlp[0].split(' [') + arLabels[3] = arTokens[0].replace('#','') + arUnits[3] = ''; + if len(arTokens) > 1: + arUnits[3] = arTokens[1].split('] ')[0] + #print(arLabels[3], arUnits[3]) + + for i in range(3): + arTokens = hlp[i*3 + 1].split() + nTokens = len(arTokens) + nTokensLabel = nTokens - 3 + nTokensLabel_mi_1 = nTokensLabel - 1 + strLabel = '' + for j in range(nTokensLabel): + strLabel += arTokens[j + 2] + if j < nTokensLabel_mi_1: strLabel += ' ' + arLabels[i] = strLabel + arUnits[i] = arTokens[nTokens - 1].replace('[','').replace(']','') + + m = _enum('T','V','H','E','HV','EV','EH','EHV') + + if ne==1 and nx==1 and ny==1 : mode = m.T + if ne==1 and nx==1 and ny>1 : mode = m.V + if ne==1 and nx>1 and ny==1 : mode = m.H + if ne>1 and nx==1 and ny==1 : mode = m.E + if ne==1 and nx>1 and ny>1 : mode = m.HV + if ne>1 and nx==1 and ny>1 : mode = m.EV + if ne>1 and nx>1 and ny==1 : mode = m.EH + if ne>1 and nx>1 and ny>1 : mode = m.EHV + + #print(mode) + return data, mode, allrange, arLabels, arUnits + +#**************************************************************************** +#def file_load(fname, read_labels=1, traj_report=False, traj_axis='x'): #MR20160729 +# if not traj_report: +# return _file_load(fname, read_labels) +# else: +# return _traj_file_load(fname, traj_axis) + +def file_load(fname, read_labels=1, multicolumn_data=False): #MR31102017 + if not multicolumn_data: + return _file_load(fname, read_labels) + else: + return _multicolumn_file_load(fname) + +#**************************************************************************** +def rescale(maxabsval, strval): + """Force labels to 1.0e-3 boundary which contains maxabsval + :param double maxabsval: absolute value on axis + :param str strval: units + :return (multiplier, strval): axis multiplier, axis label + """ + mult = 1 + if maxabsval>=1.0e2 and maxabsval<1.0e5: + mult = 1.0e-3 + strval = 'k'+strval + if maxabsval>=1.0e5 and maxabsval<1.0e8: + mult = 1.0e-6 + strval = 'M'+strval + if maxabsval>=1.0e8 and maxabsval<1.0e11: + mult = 1.0e-6 + strval = 'G'+strval + if maxabsval>=1.0e-4 and maxabsval<1.0e-1: + mult = 1.0e3 + strval = 'm'+strval + if maxabsval>=1.0e-7 and maxabsval<1.0e-4: + mult = 1.0e6 + strval = 'u'+strval + if maxabsval>=1.0e-10 and maxabsval<1.0e-7: + mult = 1.0e9 + strval = 'n'+strval + if maxabsval>1.0e-13 and maxabsval<1.0e-10: + mult = 1.0e12 + strval = 'p'+strval + return mult, strval + +#**************************************************************************** +def rescale_range(allrange, _ar_units, _ec=0, _xc=0, _yc=0): + """Adjust graph axis ranges and labels to be 1.0e-3 boundary + + :param tuple allrange: Order of ranges: e, x, y + :param tuple _ar_units: units for ranges [e, x, y] + :param + """ + e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + + #em = abs(np.array([e0,e1])).max() + #xm = abs(np.array([x0,x1])).max() + #ym = abs(np.array([y0,y1])).max() + + abs_e0 = abs(e0); abs_e1 = abs(e1) + em = abs_e0 + if(em < abs_e1): em = abs_e1 + + abs_x0 = abs(x0); abs_x1 = abs(x1) + xm = abs_x0 + if(xm < abs_x1): xm = abs_x1 + + abs_y0 = abs(y0); abs_y1 = abs(y1) + ym = abs_y0 + if(ym < abs_y1): ym = abs_y1 + + #mult_e, str_e = _rescale(em,"eV") + #mult_x, str_x = _rescale(xm,"m") + #mult_y, str_y = _rescale(ym,"m") + #mult_e, str_e = _rescale(em, _ar_units[0]) + #mult_x, str_x = _rescale(xm, _ar_units[1]) + #mult_y, str_y = _rescale(ym, _ar_units[2]) + mult_e, str_e = rescale(em, _ar_units[0]) + mult_x, str_x = rescale(xm, _ar_units[1]) + mult_y, str_y = rescale(ym, _ar_units[2]) + + e0s = uti_math.num_round(e0*mult_e) #this is done to avoid in the labels numbers like "12.700000000001" + e1s = uti_math.num_round(e1*mult_e) + x0s = uti_math.num_round(x0*mult_x) + x1s = uti_math.num_round(x1*mult_x) + y0s = uti_math.num_round(y0*mult_y) + y1s = uti_math.num_round(y1*mult_y) + ecs = uti_math.num_round(_ec*mult_e) + xcs = uti_math.num_round(_xc*mult_x) + ycs = uti_math.num_round(_yc*mult_y) + + #allnewrange = e0*mult_e, e1*mult_e, ne, x0*mult_x, x1*mult_x, nx, y0*mult_y, y1*mult_y, ny, _ec*mult_e, _xc*mult_x, _yc*mult_y + allnewrange = e0s, e1s, ne, x0s, x1s, nx, y0s, y1s, ny, ecs, xcs, ycs + strval = str_e, str_x, str_y + return allnewrange, strval + +#**************************************************************************** +def rescale_dim(_range, _base_unit=None): + """Adjust range and units of a value ("dimension" of a plot) to be 1.0e-3 boundary + + :param list _range: min. and max. value of a range to be adjusted + :param sting _base_unit: base unit (e.g. [m], [eV],...) + :return: tuple containing new adjusted range and unit + """ + + #xm = abs(np.array([_range[0], _range[1]])).max() + abs_x0 = abs(_range[0]); abs_x1 = abs(_range[1]) + xm = abs_x0 + if(xm < abs_x1): xm = abs_x1 + + mult, unit = rescale(xm, _base_unit) + newrange = deepcopy(_range) + newrange[0] *= mult; newrange[1] *= mult + return newrange, unit + +#**************************************************************************** +def _enum(*sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + return type('Enum', (), enums) + diff --git a/env/release/srw_python/uti_plot_matplotlib.py b/env/release/srw_python/uti_plot_matplotlib.py new file mode 100644 index 00000000..f49bb843 --- /dev/null +++ b/env/release/srw_python/uti_plot_matplotlib.py @@ -0,0 +1,706 @@ +"""uti_plot backend for matplotlib + +.. moduleauthor:: N. Canestrari, O. Chubar, R. Nagler, M. Rakitin +""" +import os +import sys +import subprocess +import platform +from array import * +from math import * +import numpy as np +import uti_plot_com +import uti_math +import uti_plot + +class Backend(object): + def __init__(self, backend, fname_format): + """Set matplotlib backend depending on IPython state, mpld3 availability and fname_format + Tries `backend` based on what the execution context is (IPython, X11, etc.). + Will throw exception if matplotlib or pyplot cannot be imported. + + :param str backend: attempted backend + :param str fname_format: where to save figs + """ + import matplotlib + if self._running_in_ipython(): + backend = self._init_ipython(backend) + import matplotlib.pyplot + self._pl = matplotlib.pyplot + else: + if backend == uti_plot.DEFAULT_BACKEND: + (backend, fname_format) = self._default_backend(fname_format) + matplotlib.use(backend) + import matplotlib.pyplot + self._pl = matplotlib.pyplot + matplotlib.pyplot.ioff() + (backend, fname_format) = self._verify_pyplot(backend, fname_format) + if fname_format is not None: + print('Saving figures to ' + fname_format) + self._backend = backend + self._fname_format = fname_format + self._figure_num = 0 + + def uti_plot_show(self): + 'Render the plots generated thus far; Prompts user to do the generation' + self._pyplot_show() + + #def plot1D(ar1d,x_range,labels=('energy, KeV','Ph/s/0.1%BW')): + def uti_plot1d(self, ar1d, x_range, labels=('Photon Energy [eV]', 'ph/s/0.1%bw')): + #fig = _pl.figure(figsize=(12,8)) + fig = self._pl.figure() + self._plot_1D(ar1d,x_range,labels,fig) + return self._maybe_savefig(fig) + + def uti_plot1d_ir(self, arY, arX, labels=('Longitudinal Position [m]', 'Horizontal Position [m]')): #1D plot on irregular mesh + fig = self._pl.figure() + self._plot_1D_ir(arY, arX, labels, fig) + return self._maybe_savefig(fig) + + #def plot2D(ar2d,x_range,y_range,labels=('Horizontal position, mm','Vertical position, mm')): + def uti_plot2d(self, ar2d, x_range, y_range, labels=('Horizontal Position [m]','Vertical Position [m]')): + #fig = _pl.figure(figsize=(12,8)) + fig = self._pl.figure() + self._plot_2D(ar2d,x_range,y_range,labels,fig) + return self._maybe_savefig(fig) + + def uti_plot2d1d(self, data, x_range, y_range, xc, yc, labels, _graphs_joined=True): + x0 = x_range[0]; x1 = x_range[1]; nx = x_range[2] + #y0 = x_range[0]; y1 = y_range[1]; ny = y_range[2] + y0 = y_range[0]; y1 = y_range[1]; ny = y_range[2] #OC090714 + + label2D = labels[0]; label1H = labels[1]; label1V = labels[2] + + fig = None + if _graphs_joined: + #fig = _pl.figure(figsize=(12,5)) + fig = self._pl.figure(figsize=(15,5.3)) + + self._plot_2D(data, x_range, y_range, label2D, fig, 131) #showing graphs in one panel + else: self.uti_plot2d(data, x_range, y_range, label2D) + + xStep = 0 + if nx > 1: xStep = (x1 - x0)/(nx - 1) + yStep = 0 + if ny > 1: yStep = (y1 - y0)/(ny - 1) + inperpOrd = 1 #interpolation order to use (1 to 3) + + #_plot_1D(data[iy,:],range_x,label1H,fig,132) + arCutX = array('d', [0]*nx) + xx = x0 + for ix in range(nx): + arCutX[ix] = uti_math.interp_2d(xx, yc, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + xx += xStep + if _graphs_joined: self._plot_1D(arCutX, x_range, label1H, fig, 132) #OC150814 + else: self.uti_plot1d(arCutX, x_range, label1H) + + #_plot_1D(data[:,ix],range_y,label1V,fig,133) + arCutY = array('d', [0]*ny) + yy = y0 + for iy in range(ny): + #arCutY[iy] = _interp_2d(xc, yy, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + arCutY[iy] = uti_math.interp_2d(xc, yy, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + yy += yStep + if _graphs_joined: self._plot_1D(arCutY, y_range, label1V, fig, 133) + else: self.uti_plot1d(arCutY, y_range, label1V) + + if _graphs_joined: self._pl.tight_layout() #OC081115 + + return self._maybe_savefig(fig) + + #def srw_ascii_plot(fname): + #def uti_data_file_plot(self, _fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=1): + #def uti_data_file_plot(self, _fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=1, _traj_report=False, _traj_axis='x'): #MR20160729 + #def uti_data_file_plot(self, _fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=1, _traj_report=False, _traj_axis='x', _scale='linear', _width_pixels=None): #MR27012017 + def uti_plot_data_file(self, _fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=1, #OC16112017 (renamed: uti_plot_data_file -> uti_plot_data_file) + _multicolumn_data=False, _column_x=None, _column_y=None, #MR31102017 + _scale='linear', _width_pixels=None): + #data, mode, allrange = srw_ascii_load(fname) + #data, mode, allrange, arLabels, arUnits = _file_load(_fname, _read_labels) + #data, mode, allrange, arLabels, arUnits = uti_plot_com.file_load(_fname, _read_labels) + #data, mode, allrange, arLabels, arUnits = uti_plot_com.file_load(_fname, _read_labels, _traj_report, _traj_axis) #MR20160729 + + #data = np.array(data) #MR27012017 (lines added until "pass") + #if _scale != 'linear': + # available_scales = ['log', 'log2', 'log10'] + # if _scale not in available_scales: + # raise ValueError('Scale "{}" is not supported. Available scales: {}.'.format(_scale, ', '.join(available_scales))) + # data[np.where(data <= 0.)] = 1.e-23 + # data = getattr(np, _scale)(data) + #if _width_pixels: + # try: + # from scipy.ndimage import zoom + # data = np.reshape(data, (allrange[5], allrange[8]), order='f') + # resize_factor = float(_width_pixels) / float(allrange[5]) + # print('Size before: {} Dimensions: {}'.format(data.size, data.shape)) + # data = zoom(data, resize_factor) + # if _scale == 'linear': + # data[np.where(data < 0.)] = 0.0 + # print('Size after : {} Dimensions: {}'.format(data.size, data.shape)) + # allrange = list(allrange) + # allrange[5] = data.shape[0] + # allrange[8] = data.shape[1] + # allrange = tuple(allrange) + # data = np.reshape(data, (data.shape[0] * data.shape[1]), order='f') + # except: + # print('Cannot resize the image - scipy.ndimage.zoom() cannot be imported.') + # pass + + data, mode, allrange, arLabels, arUnits = uti_plot_com.file_load(_fname, _read_labels, _multicolumn_data) #MR31102017 + if not _multicolumn_data: + data = np.array(data) + #if mode == 3: #OC17112017 (commented-out) + # try: + # fwhm_dict = uti_math.fwhm(np.linspace(allrange[0], allrange[1], allrange[2]), data, return_as_dict=True) + # except: + # fwhm_dict = {'fwhm': -1} + # print('FWHM: {:.5f} [{}]'.format(fwhm_dict['fwhm'], arUnits[0])) + if _scale != 'linear': + available_scales = ['log', 'log2', 'log10'] + if _scale not in available_scales: + raise ValueError('Scale "{}" is not supported. Available scales: {}.'.format(_scale, ', '.join(available_scales))) + data[np.where(data <= 0.)] = 1.e-23 + data = getattr(np, _scale)(data) + if _width_pixels: + try: + from scipy.ndimage import zoom + data = np.reshape(data, (allrange[5], allrange[8]), order='C') + resize_factor = float(_width_pixels) / float(allrange[5]) + print('Size before: {} Dimensions: {}'.format(data.size, data.shape)) + data = zoom(data, resize_factor) + if _scale == 'linear': + data[np.where(data < 0.)] = 0.0 + print('Size after : {} Dimensions: {}'.format(data.size, data.shape)) + allrange = list(allrange) + allrange[5] = data.shape[0] + allrange[8] = data.shape[1] + allrange = tuple(allrange) + data = np.reshape(data, (data.shape[0] * data.shape[1]), order='C') + except: + print('Cannot resize the image - scipy.ndimage.zoom() cannot be imported.') + pass + + #print(allrange) + m = self._enum('T','V','H','E','HV','EV','EH','EHV') + if mode==m.T: + fig = self.__mode_T(data, allrange, arLabels, arUnits, _e, _x, _y) + elif mode==m.V: + fig = self.__mode_V(data, allrange) + elif mode==m.H: + fig = self.__mode_H(data, allrange) + elif mode==m.E: + fig = self.__mode_E(data, allrange, arLabels, arUnits) + elif mode==m.HV: + fig = self.__mode_HV(data, allrange, arLabels, arUnits, _x, _y, _graphs_joined) + #elif mode==m.EV: + # fig = __mode_EV(data,allrange) + #elif mode==m.EH: + # fig = __mode_EH(data,allrange) + elif mode==m.EHV: + fig = self.__mode_EHV(data, allrange, arLabels, arUnits, _e, _x, _y, _graphs_joined) + + if _multicolumn_data: #MR31102017 + available_cols = list(data.keys()) + for c in [_column_x, _column_y]: + if c not in available_cols: + raise ValueError('Incorrect column specified: {}.\nAvailable columns: {}'.format(c, available_cols)) + fig = self._plot_1D_XvsY(data, _column_x, _column_y) + + return self._maybe_savefig(fig) + + def uti_data_file_plot(self, _fname, _read_labels=1, _e=0, _x=0, _y=0, _graphs_joined=1, + _multicolumn_data=False, _column_x=None, _column_y=None, #MR31102017 + _scale='linear', _width_pixels=None): + return self.uti_plot_data_file(_fname, _read_labels, _e, _x, _y, _graphs_joined, _multicolumn_data, _column_x, _column_y, _scale, _width_pixels) #OC16112017 + + def _enum(self, *sequential, **named): #Had to copy this in uti_plot_com + enums = dict(zip(sequential, range(len(sequential))), **named) + return type('Enum', (), enums) + + def _plot_1D_XvsY(self, data, column_x, column_y, figsize=(8, 5), typ=111): #MR31102017 + fig = self._pl.figure(figsize=figsize) + ax = fig.add_subplot(typ) + ax.plot(data[column_x]['data'], data[column_y]['data']) + ax.grid() + ax.set_xlabel(data[column_x]['label']) + ax.set_ylabel(data[column_y]['label']) + return fig + + def _plot_1D_ir(self, ary, arx, labels, fig, typ=111): #OC15112017 + if isinstance(arx, (list, array)): arx = np.array(arx) + if isinstance(ary, (list, array)): ary = np.array(ary) + + ax = fig.add_subplot(typ) + ax.plot(arx, ary) + ax.grid() + #ax.set_xlim(arx[0], arx[-1]) + #ax.set_xlim(min(arx), max(arx)) + + ax.set_xlabel(labels[0]) + ax.set_ylabel(labels[1]) + if(len(labels) > 2): + ax.set_title(labels[2]) + + def _plot_1D(self, ar1d, x_range, labels, fig, typ=111): + lenAr1d = len(ar1d) + if lenAr1d > x_range[2]: ar1d = np.array(ar1d[0:x_range[2]]) + elif lenAr1d < x_range[2]: + auxAr = array('d', [0]*x_range[2]) + for i in range(lenAr1d): auxAr[i] = ar1d[i] + ar1d = np.array(auxAr) + + if isinstance(ar1d,(list,array)): ar1d = np.array(ar1d) + + x = np.linspace(x_range[0],x_range[1],x_range[2]) + ax = fig.add_subplot(typ) + ax.plot(x,ar1d) + ax.grid() + ax.set_xlim(x[0],x[-1]) + ax.set_xlabel(labels[0]) + ax.set_ylabel(labels[1]) + if(len(labels) > 2): + ax.set_title(labels[2]) + + def _plot_2D(self, ar2d, x_range, y_range, labels, fig, typ=111): + totLen = int(x_range[2]*y_range[2]) + lenAr2d = len(ar2d) + if lenAr2d > totLen: ar2d = np.array(ar2d[0:totLen]) + elif lenAr2d < totLen: + auxAr = array('d', [0]*lenAr2d) + for i in range(lenAr2d): auxAr[i] = ar2d[i] + ar2d = np.array(auxAr) + + #if isinstance(ar2d,(list,array)): ar2d = np.array(ar2d).reshape(x_range[2],y_range[2]) + if isinstance(ar2d,(list,array)): ar2d = np.array(ar2d) + ar2d = ar2d.reshape(y_range[2],x_range[2]) + + x = np.linspace(x_range[0],x_range[1],x_range[2]) + y = np.linspace(y_range[0],y_range[1],y_range[2]) + ax = fig.add_subplot(typ) + #ax.pcolormesh(x,y,ar2d.T,cmap=_pl.cm.Greys_r) + #ax.pcolormesh(x,y,ar2d,cmap=_pl.cm.Greys_r) + ax.pcolormesh(x,y,ar2d,cmap=self._pl.cm.Greys_r) #OC150814 + + ax.set_xlim(x[0],x[-1]) + ax.set_ylim(y[0],y[-1]) + ax.set_xlabel(labels[0]) + ax.set_ylabel(labels[1]) + if(len(labels) > 2): + ax.set_title(labels[2]) + + def __mode_T(self, data, allrange, _ar_labels, _ar_units, _ec=0, _xc=0, _yc=0): + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units, _ec, _xc, _yc) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units, _ec, _xc, _yc) + + #e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + #toprint = (e0,e1,units[0], x0,x1,units[1], y0,y1,units[2], data[0]) #squeeze have reduced it to an array with one element. + toprint = (e0,units[0], x0,units[1], y0,units[2], data[0],units[3]) #squeeze have reduced it to an array with one element. + #sys.stdout.write('Total Flux for \nE: %f -> %f %s\nX: %f -> %f %s\nY: %f -> %f %s\n is %f Ph/s/0.1%BW' % toprint) + sys.stdout.write(_ar_labels[3] + ' for \n' + _ar_labels[0] + ': %f %s\n' + _ar_labels[1] + ': %f %s\n' + _ar_labels[2] + ': %f %s\n is %f %s' % toprint) + return None + + def __mode_V(self, data, allrange, _ar_labels, _ar_units): + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units) + + #e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + range_y = y0, y1, ny + #label = ("Vertical Position, ["+units[2]+"]","Ph/s/0.1%BW/mm^2") + label = (_ar_labels[2] + ' [' + units[2] + ']', _ar_labels[3] + ' [' + _ar_units[3] + ']') + fig = self._pl.figure(figsize=(4,4)) + self._plot_1D(data, range_y, label, fig) + return fig + + def __mode_H(self, data, allrange, _ar_labels, _ar_units): + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units) + + #e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + range_x = x0, x1, nx + #label = ("Horizontal Position, ["+units[1]+"]","Ph/s/0.1%BW/mm^2") + label = (_ar_labels[1] + ' [' + units[1] + ']', _ar_labels[3] + ' [' + _ar_units[3] + ']') + fig = self._pl.figure(figsize=(4,4)) + self._plot_1D(data, range_x, label, fig) + return fig + + def __mode_E(self, data, allrange, _ar_labels, _ar_units): + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units) + + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + range_e = e0, e1, ne + #label = ("Energy, ["+units[0]+"]","Ph/s/0.1%BW") + label = (_ar_labels[0] + ' [' + units[0] + ']', _ar_labels[3] + ' [' + _ar_units[3] + ']') + #fig = self._pl.figure(figsize=(4,4)) + fig = self._pl.figure(figsize=(7,4)) #OC17112017 + self._plot_1D(data,range_e,label,fig) + return fig + + def __mode_HV(self, data, allrange, _ar_labels, _ar_units, _xc=0, _yc=0, _graphs_joined=True): + #Could be moved to uti_plot_com.py (since there is not Matplotlib-specific content) + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units, 0, _xc, _yc) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units, 0, _xc, _yc) + + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + range_x = x0, x1, nx + range_y = y0, y1, ny + #print range_x, range_y + #x = np.linspace(x0, x1, nx) + #y = np.linspace(y0, y1, ny) + #ix = np.where(abs(x)==abs(x).min())[0][0] + #iy = np.where(abs(y)==abs(y).min())[0][0] + #label2D = ("Horizontal Position, ["+units[1]+"]", "Vertical Position, ["+units[2]+"]") + strTitle = _ar_labels[3] + if (ne == 1) and (e0 > 0): strTitle += ' at ' + str(e0) + ' ' + units[0] + + label2D = (_ar_labels[1] + ' [' + units[1]+ ']', _ar_labels[2] + ' [' + units[2] + ']', strTitle) + #print(label2D) + + #label1H = ("Horizontal Position, ["+units[1]+"]","Ph/s/0.1%BW/mm^2") + strTitle = 'At ' + _ar_labels[2] + ': ' + str(yc) + if yc != 0: strTitle += ' ' + units[2] + label1H = (_ar_labels[1] + ' [' + units[1] + ']', _ar_labels[3] + ' [' + _ar_units[3] + ']', strTitle) + + #label1V = ("Vertical Position, ["+units[2]+"]","Ph/s/0.1%BW/mm^2") + strTitle = 'At ' + _ar_labels[1] + ': ' + str(xc) + if xc != 0: strTitle += ' ' + units[1] + label1V = (_ar_labels[2] + ' [' + units[2] + ']', _ar_labels[3] + ' [' + _ar_units[3] + ']', strTitle) + + #return plot_2D_1D(data, range_x, range_y, [label2D, label1H, label1V], _graphs_joined) + return self.uti_plot2d1d(data, range_x, range_y, xc, yc, [label2D, label1H, label1V], _graphs_joined) + + ## fig = None + ## if _graphs_joined: + ## fig = _pl.figure(figsize=(12,5)) + ## _plot_2D(data, range_x, range_y, label2D, fig, 131) #showing graphs in one figure + ## else: uti_plot2d(data, range_x, range_y, label2D) + ## + ## xStep = 0 + ## if nx > 1: xStep = (x1 - x0)/(nx - 1) + ## yStep = 0 + ## if ny > 1: yStep = (y1 - y0)/(ny - 1) + ## inperpOrd = 1 #interpolation order (1 to 3) + ## + ## #_plot_1D(data[iy,:],range_x,label1H,fig,132) + ## arCutX = array('d', [0]*nx) + ## xx = x0 + ## for ix in range(nx): + ## #arCutX[ix] = _interp_2d(xx, yc, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + ## arCutX[ix] = uti_math.interp_2d(xx, yc, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + ## xx += xStep + ## if _graphs_joined: _plot_1D(arCutX, range_x, label1H, fig, 132) + ## else: uti_plot1d(arCutX, range_x, label1H) + ## + ## #_plot_1D(data[:,ix],range_y,label1V,fig,133) + ## arCutY = array('d', [0]*ny) + ## yy = y0 + ## for iy in range(ny): + ## #arCutY[iy] = _interp_2d(xc, yy, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + ## arCutY[iy] = uti_math.interp_2d(xc, yy, x0, xStep, nx, y0, yStep, ny, data, inperpOrd, 1, 0) + ## yy += yStep + ## if _graphs_joined: _plot_1D(arCutY, range_y, label1V, fig, 133) + ## else: uti_plot1d(arCutY, range_y, label1V) + ## + ## return fig + + #def __mode_EV(data, allrange): + # #to be updated + # allrange, units = _rescale_range(allrange) + # e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + # range_e = e0, e1, ne + # range_y = y0, y1, ny + # e = np.linspace(e0, e1, ne) + # y = np.linspace(y0, y1, ny) + # ie = np.where(data.sum(axis=1)==data.sum(axis=1).max())[0][0] + # iy = np.where(abs(y).min())[0][0] + # label1E = ("Energy, ["+units[0]+"]","Ph/s/0.1%BW/mm^2") + # label1V = ("Vertical Position, ["+units[2]+"]","Ph/s/0.1%BW/mm^2") + # fig = _pl.figure(figsize=(8,4)) + # _plot_1D(data[iy,:],range_e,label1E,fig,121) + # _plot_1D(data[:,ie],range_y,label1V,fig,122) + # return fig + + #def __mode_EH(data, allrange): + # #to be updated + # allrange, units = _rescale_range(allrange) + # e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + # range_e = e0, e1, ne + # range_x = x0, x1, nx + # e = np.linspace(e0, e1, ne) + # x = np.linspace(x0, x1, nx) + # ie = np.where(data.sum(axis=1)==data.sum(axis=1).max())[0][0] + # ix = np.where(abs(y).min())[0][0] + # label1E = ("Energy, ["+units[0]+"]","Ph/s/0.1%BW/mm^2") + # label1H = ("Horizontal Position, ["+units[1]+"]","Ph/s/0.1%BW/mm^2") + # fig = _pl.figure(figsize=(8,4)) + # _plot_1D(data[ix,:],range_e,label1E,fig,121) + # _plot_1D(data[:,ie],range_x,label1H,fig,122) + # return fig + + def __mode_EHV(self, data, allrange, _ar_labels, _ar_units, _ec, _xc, _yc, _graphs_joined=1): + #allrange, units = _rescale_range(allrange) + #allrange, units = _rescale_range(allrange, _ar_units, _ec, _xc, _yc) + allrange, units = uti_plot_com.rescale_range(allrange, _ar_units, _ec, _xc, _yc) + + #e0, e1, ne, x0, x1, nx, y0, y1, ny = allrange + e0, e1, ne, x0, x1, nx, y0, y1, ny, ec, xc, yc = allrange + + #e = np.linspace(e0, e1, ne) + #x = np.linspace(x0, x1, nx) + #y = np.linspace(y0, y1, ny) + #ie = np.where(data.sum(axis=1)==data.sum(axis=1).max())[0][0] + #ix = np.where(abs(x)==abs(x).min())[0][0] + #iy = np.where(abs(y)==abs(y).min())[0][0] + + range_e = e0, e1, ne + range_x = x0, x1, nx + range_y = y0, y1, ny + + ie = 0 + if ne > 1: + if ec > e1: ie = ne - 1 + elif ec > e0: + eStep = (e1 - e0)/(ne - 1) + if eStep > 0: ie = int(round((ec - e0)/eStep)) + ix = 0 + if nx > 1: + if xc > x1: ix = nx - 1 + elif xc > x0: + xStep = (x1 - x0)/(nx - 1) + if xStep > 0: ix = int(round((xc - x0)/xStep)) + iy = 0 + if ny > 1: + if yc > y1: iy = ny - 1 + elif yc > y0: + yStep = (y1 - y0)/(ny - 1) + if yStep > 0: iy = int(round((yc - y0)/yStep)) + + #label2D = ("Horizontal Position, ["+units[1]+"]", "Vertical Position, ["+units[2]+"]") + label2D = (_ar_labels[1] + ' [' + units[1] + ']', _ar_labels[2] + ' [' + units[2] + ']') + + #label1E = ("Energy, ["+units[0]+"]","Ph/s/0.1%BW/mm^2") + label1E = (_ar_labels[0] + ' [' + units[0] + ']', _ar_labels[3] + ' [' + units[3] + ']') + + #label1H = ("Horizontal Position, ["+units[1]+"]","Ph/s/0.1%BW/mm^2") + label1H = (_ar_labels[1] + ' [' + units[1] + ']', _ar_labels[3] + ' [' + units[3] + ']') + + #label1V = ("Vertical Position, ["+units[2]+"]","Ph/s/0.1%BW/mm^2") + label1V = (_ar_labels[2] + ' [' + units[2] + ']', _ar_labels[3] + ' [' + units[3] + ']') + + arCutXY = array('d', [0]*nx*ny) + perY = ne*nx + i = 0 + for iiy in range(ny): + perY_iiy = perY*iiy + for iix in range(nx): + arCutXY[i] = data[ie + ne*iix + perY_iiy] + i += 1 + + arCutE = array('d', [0]*ne) + perX_ix = ne*ix + perY_iy = perY*iy + for iie in range(ne): arCutE[iie] = data[iie + perX_ix + perY_iy] + + arCutX = array('d', [0]*nx) + for iix in range(nx): arCutX[iix] = data[ie + ne*iix + perY_iy] + + arCutY = array('d', [0]*ny) + for iiy in range(ny): arCutY[iiy] = data[ie + perX_ix + perY*iiy] + + #fig = _pl.figure(figsize=(8,8)) + #_plot_2D(data[:,:,ie], range_x, range_y, label2D, fig, 221) + #_plot_1D(data[ix,iy,:],range_e,label1E,fig,224) + #_plot_1D(data[ie,:,iy],range_x,label1H,fig,222) + #_plot_1D(data[:,ix,ie],range_y,label1V,fig,223) + + fig = None + if _graphs_joined: + fig = self._pl.figure(figsize=(12,5)) + self._plot_2D(arCutXY, range_x, range_y, label2D, fig, 221) #showing graphs in one figure + self._plot_1D(arCutE, range_e, label1E, fig, 222) + self._plot_1D(arCutX, range_x, label1X, fig, 223) + self._plot_1D(arCutY, range_y, label1Y, fig, 224) + else: + self.uti_plot2d(arCutXY, range_x, range_y, label2D) + self.uti_plot1d(arCutE, range_e, label1E) + self.uti_plot1d(arCutX, range_x, label1X) + self.uti_plot1d(arCutY, range_y, label1Y) + return self._maybe_savefig(fig) + + def _maybe_savefig(self, figure): + """If there is an ``fname_format``, then save the pyplot `figure` + (if not None) to the computed file name + """ + if figure is None: + return figure + if self._fname_format is None: + return figure + figure.savefig(self._fname_format.format(self._figure_num)) + self._figure_num += 1 + return figure + + def _pyplot_show(self): + """'Render the plots, if the backend is interactive. + Plots saved to files (``fname_format``), have already been written. + """ + with self._HideGUIErrorOutput(): + self._pl.show() + + def _default_fname_format(self): + """Use main program's name (or uti_plot if none) for default file format name. + The default file type is png + """ + try: + base = os.path.splitext( + os.path.basename(sys.modules['__main__']['__file__'])) + except: + base = 'uti_plot' + fname_format = base + '-{}.png' + return fname_format + + def _default_backend(self, fname_format): + """Selects backend based on execution context (X11, macosx, etc.). If an + interactive backend is not possible, return _default_file_backend() + """ + if self._running_in_x11() or self._running_in_windows(): + backend = 'TkAgg' + elif self._running_in_macosx(): + backend = 'macosx' + else: + (backend, fname_format) = self._default_file_backend(fname_format) + return (backend, fname_format) + + def _default_file_backend(self, fname_format): + """Returns "agg" for backend with fname_format. If fname_format is none, + calls _default_fname_format() to compute fname_format. + """ + if fname_format is None: + fname_format = self._default_fname_format() + return ('agg', fname_format) + + def _init_ipython(self, backend): + """Tries `backend`. Returns ``inline`` backend if default requested or + unable to load requested backend. + """ + if backend == uti_plot.DEFAULT_BACKEND: + backend = 'inline' + is_mpld3 = backend == 'mpld3' + b = 'inline' if is_mpld3 else backend + get_ipython().magic('matplotlib ' + b) + if is_mpld3: + try: + import mpld3 + mpld3.enable_notebook() + except: + print('mpld3: backend unavailable; plots will be inline') + backend = 'inline' + return backend + + def _verify_pyplot(self, backend, fname_format): + """Create a pyplot figure and close it to be sure backend functions properly. + If backend fails, configures _default_file_backend(). + """ + import matplotlib.pyplot + pl = matplotlib.pyplot + try: + pl.figure(figsize=(0,0)) + pl.close('all') + except: + old = backend + (backend, fname_format) = self._default_file_backend(fname_format) + pl.switch_backend(backend) + # If this raises an exception, uti_plot will set backend to None + pl.figure() + pl.close('all') + print(old + ': backend unavailable; plots will be saved to files') + return (backend, fname_format) + + def _running_in_ipython(self): + 'Is the current interpreter IPython?' + try: + __IPYTHON__ + return True + except NameError: + return False + + def _running_in_macosx(self): + 'Is Mac OS X running?' + return platform.system() == 'Darwin' + + def _running_in_windows(self): + 'Is Darwin running?' + return platform.system() == 'Windows' + + def _running_in_x11(self): + 'Is X11 running?' + d = os.environ.get('DISPLAY') + if d is None or d == '': + return False + devnull = open(os.devnull, 'wb') + tries = [ + # xset is not in core install on some OSes + ['xset', '-q'], + # This takes a couple of seconds + ['xterm', '/bin/true']] + for t in tries: + try: + subprocess.call(t, stdout=devnull, stderr=devnull) + return True + except: + pass + #return false + return False #MR19042016 + + class _HideGUIErrorOutput(object): + """Redirect low level stderr (fd #2) to os.devnull as context manager + + TkAgg has a bug:: + + can't invoke "event" command: application has been destroyed + while executing + "event generate $w <>" + (procedure "ttk::ThemeChanged" line 6) + invoked from within + "ttk::ThemeChanged" + + The output comes from C so it has to be redirected at the file descriptor + level. This class does the low level redirection so that message doesn't + come out. Example:: + + with HideGUIErrorOutput(): + pl.show() + """ + def __init__(self): + pass + + def __enter__(self): + 'Redirects stderr to devnull, saving _prev_stderr' + if sys.stderr is None or sys.__stderr__ is None: + return + sys.stderr.flush() + fno = sys.__stderr__.fileno() #OC150814 + if(fno >= 0): + null = os.open(os.devnull, os.O_WRONLY) + #self._prev_stderr = os.dup(sys.__stderr__.fileno()) + self._prev_stderr = os.dup(fno) + os.dup2(null, sys.__stderr__.fileno()) + os.close(null) + + def __exit__(self, exc_type, exc_value, traceback): + 'Redirects to _prev_stderr' + if sys.stderr is None or sys.__stderr__ is None: + return + sys.__stderr__.flush() + fno = sys.__stderr__.fileno() #OC150814 + if(fno >= 0): + #os.dup2(self._prev_stderr, sys.__stderr__.fileno()) + os.dup2(self._prev_stderr, fno) + os.close(self._prev_stderr) diff --git a/env/work/pre_releases/srw_python_Mar2013.zip b/env/work/pre_releases/srw_python_Mar2013.zip deleted file mode 100644 index 8b06d19d..00000000 Binary files a/env/work/pre_releases/srw_python_Mar2013.zip and /dev/null differ diff --git a/env/work/pre_releases/srw_python_Nov2012.zip b/env/work/pre_releases/srw_python_Nov2012.zip deleted file mode 100644 index c5a27192..00000000 Binary files a/env/work/pre_releases/srw_python_Nov2012.zip and /dev/null differ diff --git a/env/work/srw_python/ReadMe.txt b/env/work/srw_python/ReadMe.txt index a7f46dfd..e695a4c8 100644 --- a/env/work/srw_python/ReadMe.txt +++ b/env/work/srw_python/ReadMe.txt @@ -4,8 +4,8 @@ Comments to "SRWLIB" for Python (November 2017) Basic content and installation of the SRWLIB package: ---------------------------------------------------- -- srwlpy.pyd, srwlpy.so are SRW Python bindings (shared libraries) compiled for Windows and Linux respectively. Note that there is no guarantee that these files, located in ../srw_python/, are compatible with the versions of operating system and Python that you are using. -The compiled shared library files for Python 3.x and 2.7 for 64- and 32-bit Windows and Linux are available in ../srw_python/lib/. The file names of the compiled shared libraries are self-explanatory: e.g. srwlpy3_6_x64.pyd is a version for Python 3.6 for Windows 64 bit; srwlpy2_7_x86_64.so is for Python 2.7 for Linux 64 bit. Copy the compiled shared library file corresponding to your operating system and Python versions from ../srw_python/lib/ to ../srw_python/ and change its name to srwlpy.pyd (on Windows) or srwlpy.so (on Linux) e.g.: +- srwlpy.pyd, srwlpy.so are SRW Python bindings (shared libraries) compiled for Windows and Linux respectively. Note that there is no guarantee that these files, located in ../srw_python/, are compatible with the versions of operating system and Python that you are using. NOTE: if these files are not compatible with the versions of system libraries or Python that you are using, you can always re-compile these, following the guidelines given in the README.txt file located in the main directory of the SRW repository. +Several pre-compiled shared library files for Python 3.x and 2.7 for 64- and 32-bit Windows and Linux are available in ../srw_python/lib/. The file names of the compiled shared libraries are self-explanatory: e.g. srwlpy3_6_x64.pyd is a version for Python 3.6 for Windows 64 bit; srwlpy2_7_x86_64.so is for Python 2.7 for Linux 64 bit. Copy the compiled shared library file corresponding to your operating system and Python versions from ../srw_python/lib/ to ../srw_python/ and change its name to srwlpy.pyd (on Windows) or srwlpy.so (on Linux) e.g.: on Windows: copy ..\srw_python\lib\srwlpy3_6_x64.pyd ..\srw_python\srwlpy.pyd on Linux: @@ -35,8 +35,8 @@ Optional configuring of Python and SRWLIB on Linux: Make sure that path to Python 3.6 (or 2.7) is added to the PATH variable and "srw_python" directory to PYTHONPATH variable: export PATH="$PATH:" #this is not necessary if you install python using the distro's package manager -export PYTHONPATH="$PYTHONPATH:SRW_Dev/work/srw_python/" #temporarely solution +export PYTHONPATH="$PYTHONPATH:SRW_Dev/work/srw_python/" #temporary solution or: -echo "export PYTHONPATH=$PYTHONPATH:SRW_Dev/work/srw_python/" >> ~/.bashrc # permanent solution for a single user +echo "export PYTHONPATH=$PYTHONPATH:SRW_Dev/work/srw_python/" >> ~/.bashrc #permanent solution for a single user Setting up PYTHONPATH allows to import srwlpy module from any directory. diff --git a/env/work/srw_python/lib/libsrw_x86_64.a b/env/work/srw_python/lib/libsrw_x86_64.a index 9eb1c7cb..b10bd095 100644 Binary files a/env/work/srw_python/lib/libsrw_x86_64.a and b/env/work/srw_python/lib/libsrw_x86_64.a differ diff --git a/env/work/srw_python/lib/libsrw_x86_64.a.old b/env/work/srw_python/lib/libsrw_x86_64.a.old index 0a741a59..9eb1c7cb 100644 Binary files a/env/work/srw_python/lib/libsrw_x86_64.a.old and b/env/work/srw_python/lib/libsrw_x86_64.a.old differ diff --git a/env/work/srw_python/lib/srw_win32.lib b/env/work/srw_python/lib/srw_win32.lib index 7bf4c174..0b570347 100644 Binary files a/env/work/srw_python/lib/srw_win32.lib and b/env/work/srw_python/lib/srw_win32.lib differ diff --git a/env/work/srw_python/lib/srw_x64.lib b/env/work/srw_python/lib/srw_x64.lib index ccfe9c91..83e7e286 100644 Binary files a/env/work/srw_python/lib/srw_x64.lib and b/env/work/srw_python/lib/srw_x64.lib differ diff --git a/env/work/srw_python/lib/srw_x64_omp.lib b/env/work/srw_python/lib/srw_x64_omp.lib new file mode 100644 index 00000000..06aeddd4 Binary files /dev/null and b/env/work/srw_python/lib/srw_x64_omp.lib differ diff --git a/env/work/srw_python/lib/srwlib.h b/env/work/srw_python/lib/srwlib.h index a7b59e0a..5d90e0a4 100644 --- a/env/work/srw_python/lib/srwlib.h +++ b/env/work/srw_python/lib/srwlib.h @@ -241,6 +241,7 @@ struct SRWLStructRadMesh { long ne, nx, ny; /* numbers of points vs photon energy, horizontal and vertical positions */ double nvx, nvy, nvz, hvx, hvy, hvz; /* lab-frame coordinate of the inner normal to observation plane (/ surface in its center) and horizontal base vector of the observation plane (/ surface in its center) */ double *arSurf; /* array defining the observation surface (as function of 2 variables - x & y - on the mesh given by _xStart, _xFin, _nx, _yStart, _yFin, _ny; to be used in case this surface differs from plane) */ + char type; /* type of data: 0- standard intensity, 'm'- mutual intensity //OC13112018 */ }; typedef struct SRWLStructRadMesh SRWLRadMesh; @@ -513,6 +514,13 @@ typedef struct SRWLStructOpticsContainer SRWLOptC; */ EXP void CALL srwlUtiSetWfrModifFunc(int (*pExtFunc)(int action, SRWLWfr* pWfrIn, char pol)); +/** + * Sets pointer to external function which allocates an array (continious memory block) in client environment. + * @param [in] pExtFunc pointer to the external function + * @see ... + */ +EXP void CALL srwlUtiSetAllocArrayFunc(char* (*pExtFunc)(char type, long long len)); //OC15082018 + /** * Sets pointer to external function to show progress of computation process * @param [in] pExtFunc pointer to the external function @@ -732,7 +740,8 @@ EXP int CALL srwlSetRepresElecField(SRWLWfr* pWfr, char repr); * @return integer error (>0) or warnig (<0) code * @see ... */ -EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt); +EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt, int nInt=0, char** arID=0, SRWLRadMesh* arIM=0, char** arI=0); //OC15082018 +//EXP int CALL srwlPropagElecField(SRWLWfr* pWfr, SRWLOptC* pOpt); /** TEST * "Propagates" multple Electric Field Wavefronts from different electrons through Optical Elements and free spaces @@ -786,6 +795,39 @@ EXP int CALL srwlUtiFFT(char* pcData, char typeData, double* arMesh, int nMesh, */ EXP int CALL srwlUtiConvWithGaussian(char* pcData, char typeData, double* arMesh, int nMesh, double* arSig); +/** + * Calculates basic statistical characteristics of intensity distribution + * @param [in, out] arInf (double) array of characteristics to be extracted: + * arInf[0]: peak (max.) intensity + * arInf[1]: position of peak intensity vs 1st dimension + * arInf[2]: position of peak intensity vs 2nd dimension + * arInf[3]: position of peak intensity vs 3rd dimension (reserved for future use) + * arInf[4]: FWHM value of intensity distribution vs 1st dimension + * arInf[5]: FWHM value of intensity distribution vs 2nd dimension + * arInf[6]: FWHM value of intensity distribution vs 3rd dimension (reserved for future use) + * @param [in] pcData (char) pointer to intensity distribution data to be analyzed + * @param [in] typeData character specifying data type ('f' for float, 'd' for double) + * @param [in] pMesh (pointer to SRWLRadMesh) mesh of intensity data to be analyzed + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiIntInf(double* arInf, char* pcData, char typeData, SRWLRadMesh* pMesh); + +/** + * Performs misc. operations on intensity distribution (or similar C-aligned) arrays + * @param [in, out] pcI1 (char) pointer to intensity distribution data #1 + * @param [in] typeI1 character specifying intensity #1 data type ('f' for float, 'd' for double) + * @param [in] pMesh1 (pointer to SRWLRadMesh) mesh of intensity data #1 + * @param [in] pcI2 (char) pointer to intensity distribution data #2 + * @param [in] typeI2 character specifying intensity #2 data type ('f' for float, 'd' for double) + * @param [in] pMesh2 (pointer to SRWLRadMesh) mesh of intensity data #2 + * @param [in] arPar array of parameters defining operation to be performed: + * arPar[0] defines type of the operation, with the meaning of other elements dependent on it + * @return integer error (>0) or warnig (<0) code + * @see ... + */ +EXP int CALL srwlUtiIntProc(char* pcI1, char typeI1, SRWLRadMesh* pMesh1, char* pcI2, char typeI2, SRWLRadMesh* pMesh2, double* arPar); + /** * Attempts to deduce parameters of peridic undulator magnetic field from tabulated field and set up Undulator structure * @param [in, out] pUndCnt pointer to magnetic field container structure with undulator structure to be set up @@ -817,6 +859,12 @@ EXP int CALL srwlUtiUndFromMagFldTab(SRWLMagFldC* pUndCnt, SRWLMagFldC* pMagCnt, */ EXP int CALL srwlUtiUndFindMagFldInterpInds(int* arResInds, int* pnResInds, double* arGaps, double* arPhases, int nVals, double arPrecPar[5]); +/** + * These functions were added by S.Yakubov (for profiling?) at parallelizing SRW via OpenMP +EXP void CALL srwlPrintTime(const char* str, double* start); +EXP void CALL get_walltime(double* wcTime); + */ + /***************************************************************************/ #ifdef __cplusplus diff --git a/env/work/srw_python/lib/srwlpy2_7_win32.pyd b/env/work/srw_python/lib/srwlpy2_7_win32.pyd index 62adf7d3..92136efe 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_win32.pyd and b/env/work/srw_python/lib/srwlpy2_7_win32.pyd differ diff --git a/env/work/srw_python/lib/srwlpy2_7_win32.pyd.old b/env/work/srw_python/lib/srwlpy2_7_win32.pyd.old index 6e167871..62adf7d3 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_win32.pyd.old and b/env/work/srw_python/lib/srwlpy2_7_win32.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy2_7_x64.pyd b/env/work/srw_python/lib/srwlpy2_7_x64.pyd index 22d82dd7..eab646f7 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_x64.pyd and b/env/work/srw_python/lib/srwlpy2_7_x64.pyd differ diff --git a/env/work/srw_python/lib/srwlpy2_7_x64.pyd.old b/env/work/srw_python/lib/srwlpy2_7_x64.pyd.old index 804e1d37..22d82dd7 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_x64.pyd.old and b/env/work/srw_python/lib/srwlpy2_7_x64.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy2_7_x86_64.so b/env/work/srw_python/lib/srwlpy2_7_x86_64.so index 2e06874e..2fe8eef4 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_x86_64.so and b/env/work/srw_python/lib/srwlpy2_7_x86_64.so differ diff --git a/env/work/srw_python/lib/srwlpy2_7_x86_64.so.old b/env/work/srw_python/lib/srwlpy2_7_x86_64.so.old index d006328d..2fe8eef4 100644 Binary files a/env/work/srw_python/lib/srwlpy2_7_x86_64.so.old and b/env/work/srw_python/lib/srwlpy2_7_x86_64.so.old differ diff --git a/env/work/srw_python/lib/srwlpy2_7_x86_64_omp.so b/env/work/srw_python/lib/srwlpy2_7_x86_64_omp.so new file mode 100644 index 00000000..599db11e Binary files /dev/null and b/env/work/srw_python/lib/srwlpy2_7_x86_64_omp.so differ diff --git a/env/work/srw_python/lib/srwlpy3_3_win32.pyd b/env/work/srw_python/lib/srwlpy3_3_win32.pyd index 6d783ac0..5b905eca 100644 Binary files a/env/work/srw_python/lib/srwlpy3_3_win32.pyd and b/env/work/srw_python/lib/srwlpy3_3_win32.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_3_win32.pyd.old b/env/work/srw_python/lib/srwlpy3_3_win32.pyd.old index a434cdd6..6d783ac0 100644 Binary files a/env/work/srw_python/lib/srwlpy3_3_win32.pyd.old and b/env/work/srw_python/lib/srwlpy3_3_win32.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy3_3_x64.pyd b/env/work/srw_python/lib/srwlpy3_3_x64.pyd index 9fe0b8cf..31996b90 100644 Binary files a/env/work/srw_python/lib/srwlpy3_3_x64.pyd and b/env/work/srw_python/lib/srwlpy3_3_x64.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_3_x64.pyd.old b/env/work/srw_python/lib/srwlpy3_3_x64.pyd.old index 1ba13224..9fe0b8cf 100644 Binary files a/env/work/srw_python/lib/srwlpy3_3_x64.pyd.old and b/env/work/srw_python/lib/srwlpy3_3_x64.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy3_5_win32.pyd b/env/work/srw_python/lib/srwlpy3_5_win32.pyd new file mode 100644 index 00000000..8eaa09c9 Binary files /dev/null and b/env/work/srw_python/lib/srwlpy3_5_win32.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_5_x64.pyd b/env/work/srw_python/lib/srwlpy3_5_x64.pyd index 36bd318e..392c08a3 100644 Binary files a/env/work/srw_python/lib/srwlpy3_5_x64.pyd and b/env/work/srw_python/lib/srwlpy3_5_x64.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_5_x64.pyd.old b/env/work/srw_python/lib/srwlpy3_5_x64.pyd.old index 31243bcb..36bd318e 100644 Binary files a/env/work/srw_python/lib/srwlpy3_5_x64.pyd.old and b/env/work/srw_python/lib/srwlpy3_5_x64.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy3_6_win32.pyd b/env/work/srw_python/lib/srwlpy3_6_win32.pyd index 31c61d60..775f9116 100644 Binary files a/env/work/srw_python/lib/srwlpy3_6_win32.pyd and b/env/work/srw_python/lib/srwlpy3_6_win32.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_6_win32.pyd.old b/env/work/srw_python/lib/srwlpy3_6_win32.pyd.old index 9175ed8e..31c61d60 100644 Binary files a/env/work/srw_python/lib/srwlpy3_6_win32.pyd.old and b/env/work/srw_python/lib/srwlpy3_6_win32.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy3_6_x64.pyd b/env/work/srw_python/lib/srwlpy3_6_x64.pyd index 186dc81f..60c96609 100644 Binary files a/env/work/srw_python/lib/srwlpy3_6_x64.pyd and b/env/work/srw_python/lib/srwlpy3_6_x64.pyd differ diff --git a/env/work/srw_python/lib/srwlpy3_6_x64.pyd.old b/env/work/srw_python/lib/srwlpy3_6_x64.pyd.old index 65547662..186dc81f 100644 Binary files a/env/work/srw_python/lib/srwlpy3_6_x64.pyd.old and b/env/work/srw_python/lib/srwlpy3_6_x64.pyd.old differ diff --git a/env/work/srw_python/lib/srwlpy3_6_x64_omp.pyd b/env/work/srw_python/lib/srwlpy3_6_x64_omp.pyd new file mode 100644 index 00000000..f595ea25 Binary files /dev/null and b/env/work/srw_python/lib/srwlpy3_6_x64_omp.pyd differ diff --git a/env/work/srw_python/srwl_bl.py b/env/work/srw_python/srwl_bl.py index 80d1ec5f..3fc76308 100644 --- a/env/work/srw_python/srwl_bl.py +++ b/env/work/srw_python/srwl_bl.py @@ -1303,7 +1303,8 @@ def calc_ur_spec_me(self, _mesh, _harm_init=1, _harm_fin=15, _prec_long=1., _pre #------------------------------------------------------------------------ #def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None): - def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None, _sr_samp_fact=-1, _det=None, _me_approx=0): #OC13042018 + #def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None, _sr_samp_fact=-1, _det=None, _me_approx=0): #OC13042018 + def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=10, _type=2, _mag=2, _pol=0, _rand_meth=1, _fname=None, _sr_samp_fact=-1, _det=None, _me_approx=0, _fbk=False): #OC14082018 """Calculates multi-electron flux of undulator radiation (within fixed aperture of per unit surface), using approximate periodic magnetic field :param _mesh: mesh on which the intensity has to be calculated (SRWLRadMesh instance) :param _meth: SR Electric Field calculation method to be used (0- "manual", 1- "auto-undulator", 2- "auto-wiggler") @@ -1353,7 +1354,9 @@ def calc_arb_spec_me(self, _mesh, _meth=2, _rel_prec=0.01, _n_part_tot=100000, _ _sr_meth = _meth, _sr_rel_prec = _rel_prec, _n_part_tot = _n_part_tot, _n_part_avg_proc = _n_part_avg_proc, _n_save_per = _n_save_per, _rand_meth = _rand_meth, #_file_path = _fname, _char = charMultiE) - _file_path = _fname, _sr_samp_fact = _sr_samp_fact, _char = charMultiE, _det = _det, _me_approx = _me_approx) #OC14042018 + _file_path = _fname, _sr_samp_fact = _sr_samp_fact, _char = charMultiE, _det = _det, _me_approx = _me_approx, #) #OC14042018 + _file_bkp = True if(_fbk == True) else False) #OC14082018 + #Consider treating detector here? arI = None @@ -1734,7 +1737,8 @@ def calc_wfr_prop(self, _wfr, _pres_ang=0, _pol=6, _int_type=0, _dep_type=3, _fn #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None): #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None): #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None): #OC06122016 - def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _in_wre=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None, _me_approx=0): #OC05042017 + #def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _in_wre=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None, _me_approx=0): #OC05042017 + def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec=0.01, _in_wr=0., _in_wre=0., _mag_type=1, _n_part_tot=100000, _n_part_avg_proc=10, _n_save_per=50, _pres_ang=0, _char=0, _x0=0, _y0=0, _e_ph_integ=0, _rand_meth=1, _fname=None, _det=None, _me_approx=0, _fbk=False): #OC14082018 """Calculates multi-electron (/ partially coherent) SR emission and wavefront propagation :param _mesh: mesh (grid) on which the initial wavefront has to be calculated (SRWLRadMesh instance) :param _sr_samp_fact: oversampling factor for calculating of initial wavefront for subsequent propagation (effective if >0) @@ -1807,7 +1811,8 @@ def calc_wfr_emit_prop_me(self, _mesh, _sr_samp_fact=1, _sr_meth=2, _sr_rel_prec #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth) #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det) #OC06122016 #_e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det, _me_approx = _multi_e_approx) #OC05042017 - _e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det, _me_approx = _me_approx) #OC14042018 + _e_ph_integ = _e_ph_integ, _rand_meth = _rand_meth, _det = _det, _me_approx = _me_approx, + _file_bkp = True if(_fbk == True) else False) #OC14082018 #------------------------------------------------------------------------ ##def srwl_uti_parse_optics_par(self, _v): @@ -2164,7 +2169,8 @@ def calc_all(self, _v, _op): _fname = os.path.join(_v.fdir, _v.sm_fn) if(len(_v.sm_fn) > 0) else '', _sr_samp_fact = _v.sm_smpf, _det = detector, - _me_approx = _v.sm_am) #OC13042018 + _me_approx = _v.sm_am, #) #OC13042018 + _fbk = True if(_v.sm_fbk) else False) #OC14082018 #---calculate undulator "operation table", i.e. dependence of gap (and phase) on photon energy (for a given polarization) if(_v.ut): @@ -2355,6 +2361,7 @@ def calc_all(self, _v, _op): if(_v.wm): #wmResFileName = os.path.join(_v.fdir, _v.wm_fni) if(len(_v.wm_fni) > 0) else None #print(wmResFileName) + #print('_v.wm_fbk=', _v.wm_fbk) res_ipm = self.calc_wfr_emit_prop_me( _mesh = mesh_w, @@ -2376,7 +2383,8 @@ def calc_all(self, _v, _op): _fname = os.path.join(_v.fdir, _v.wm_fni) if(len(_v.wm_fni) > 0) else None, _det = detector, #_multi_e_approx = _v.wm_am) - _me_approx = _v.wm_am) #OC13042018 + _me_approx = _v.wm_am, #) #OC13042018 + _fbk = True if(_v.wm_fbk) else False) #OC14082018 #---plot results of all calculatiopns here (because the plotting "from the middle of the script" may hang up script execution) #uti_plot_init('TkAgg') #make the backend name an input option or move this to uti_plot ? @@ -2793,6 +2801,7 @@ def srwl_uti_std_options(): ['sm_am', 'i', 0, 'multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance'], ['sm_fn', 's', 'res_spec_me.dat', 'file name for saving calculated milti-e spectrum vs photon energy'], ['sm_pl', 's', 'e', 'plot the resulting spectrum-e spectrum in a graph: ""- dont plot, "e"- show plot vs photon energy'], + ['sm_fbk', '', '', 'create backup file(s) with multi-e spectrum (only is it is calculated using the macro-particle method)', 'store_true'], #Power Density Distribution vs horizontal and vertical position ['pw', '', '', 'calculate SR power density distribution', 'store_true'], @@ -2877,6 +2886,7 @@ def srwl_uti_std_options(): ['wm_rm', 'i', 1, 'method for generation of pseudo-random numbers for e-beam phase-space integration: 1- standard pseudo-random number generator, 2- Halton sequences, 3- LPtau sequences (to be implemented)'], ['wm_am', 'i', 0, 'multi-electron integration approximation method: 0- no approximation (use the standard 5D integration method), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance'], ['wm_fni', 's', 'res_int_pr_me.dat', 'file name for saving propagated multi-e intensity distribution vs horizontal and vertical position'], + ['wm_fbk', '', '', 'create backup file(s) with propagated multi-e intensity distribution vs horizontal and vertical position and other radiation characteristics', 'store_true'], #['ws_fn', 's', '', 'file name for saving single-e (/ fully coherent) wavefront data'], #['wm_fn', 's', '', 'file name for saving multi-e (/ partially coherent) wavefront data'], diff --git a/env/work/srw_python/srwl_uti_smp.py b/env/work/srw_python/srwl_uti_smp.py index 26671f7e..fdfb4fe0 100644 --- a/env/work/srw_python/srwl_uti_smp.py +++ b/env/work/srw_python/srwl_uti_smp.py @@ -299,22 +299,99 @@ def srwl_opt_setup_transm_from_file( rx = nx * resolution ry = ny * resolution - opT = srwlib.SRWLOptT(_nx=nx, _ny=ny, _rx=rx, _ry=ry, - _arTr=arTr, _extTr=extTr, _Fx=fx, _Fy=fy, - _x=xc, _y=yc, _ne=ne, _eStart=e_start, _eFin=e_fin) + #opT = srwlib.SRWLOptT(_nx=nx, _ny=ny, _rx=rx, _ry=ry, + # _arTr=arTr, _extTr=extTr, _Fx=fx, _Fy=fy, + # _x=xc, _y=yc, _ne=ne, _eStart=e_start, _eFin=e_fin) data = s.data - # Same data alignment as for wavefront: outmost loop vs y, inmost loop vs e - offset = 0 - for iy in range(ny): - for ix in range(nx): + #OC10112018 + specPropAreDef = False + if(ne > 1): + if((isinstance(delta, list) or isinstance(delta, array)) and (isinstance(atten_len, list) or isinstance(atten_len, array))): + lenDelta = len(delta) + if((lenDelta == len(atten_len)) and (lenDelta == ne)): specPropAreDef = True + else: raise Exception("Inconsistent spectral refractive index decrement and/or attenuation length data") + + #OC10112018 + useNumPy = False + try: + import numpy as np + useNumPy = True + except: + print('NumPy can not be loaded, native Python arrays / lists will be used instead, impacting performance') + + if(useNumPy): #RC161018 + + thickByLim = thickness/s.limit_value + nxny = nx*ny + miHalfThickByLimByAttenLen = None + miThickDeltaByLim = None + + if(ne <= 1): + miHalfThickByLimByAttenLen = -0.5*thickByLim/atten_len + miThickDeltaByLim = -thickByLim*delta + + #amplTransm = np.exp(-0.5 * data * thickness / (s.limit_value * atten_len)) + amplTransm = np.exp(miHalfThickByLimByAttenLen*data) + + #optPathDiff = -1 * data * thickness * delta / s.limit_value + optPathDiff = miThickDeltaByLim*data + + arTr = np.empty((2*nxny), dtype=float) + arTr[0::2] = np.reshape(amplTransm, nxny) + arTr[1::2] = np.reshape(optPathDiff, nxny) + #opT.arTr = arTr + + else: + two_ne = 2*ne + arTr = np.empty((nxny*two_ne), dtype=float) + + if(specPropAreDef == False): + miHalfThickByLimByAttenLen = -0.5*thickByLim/atten_len + miThickDeltaByLim = -thickByLim*delta + for ie in range(ne): - # In images Y=0 corresponds from upper-left corner, in SRW it's lower-left corner: + if(specPropAreDef): + miHalfThickByLimByAttenLen = -0.5*thickByLim/atten_len[ie] + miThickDeltaByLim = -thickByLim*delta[ie] + + amplTransm = np.exp(miHalfThickByLimByAttenLen*data) + optPathDiff = miThickDeltaByLim*data + + two_ie = 2*ie + arTr[two_ie::two_ne] = np.reshape(amplTransm, nxny) #to check! + arTr[(two_ie + 1)::two_ne] = np.reshape(optPathDiff, nxny) + else: + #Same data alignment as for wavefront: outmost loop vs y, inmost loop vs e + nTot = 2*ne*nx*ny + arTr = array('d', [0]*nTot) + + offset = 0 + for iy in range(ny): + for ix in range(nx): + #In images Y=0 corresponds from upper-left corner, in SRW it's lower-left corner: pathInBody = thickness * data[ny - iy - 1, ix] / s.limit_value - opT.arTr[offset] = math.exp(-0.5 * pathInBody / atten_len) # amplitude transmission - opT.arTr[offset + 1] = -delta * pathInBody # optical path difference - offset += 2 + + #OC10112018 + miHalfPathInBody = -0.5*pathInBody + + if(specPropAreDef): + for ie in range(ne): + #opT.arTr[offset] = math.exp(-0.5 * pathInBody / atten_len) # amplitude transmission + #opT.arTr[offset + 1] = -delta * pathInBody # optical path difference + arTr[offset] = math.exp(miHalfPathInBody / atten_len[ie]) #amplitude transmission + arTr[offset + 1] = -delta[ie] * pathInBody #optical path difference + offset += 2 + else: + for ie in range(ne): + arTr[offset] = math.exp(miHalfPathInBody / atten_len) #amplitude transmission + arTr[offset + 1] = -delta * pathInBody #optical path difference + offset += 2 + + opT = srwlib.SRWLOptT(_nx=nx, _ny=ny, _rx=rx, _ry=ry, + _arTr=arTr, _extTr=extTr, _Fx=fx, _Fy=fy, + _x=xc, _y=yc, _ne=ne, _eStart=e_start, _eFin=e_fin) opT.input_parms = input_parms diff --git a/env/work/srw_python/srwlib.py b/env/work/srw_python/srwlib.py index 663e902f..97e51632 100644 --- a/env/work/srw_python/srwlib.py +++ b/env/work/srw_python/srwlib.py @@ -2,7 +2,7 @@ # SRWLib for Python v 0.14 ############################################################################# -from __future__ import print_function #Python 2.7 compatibility +from __future__ import absolute_import, division, print_function #Py 2.*/3.* compatibility import srwlpy as srwl from array import * from math import * @@ -827,6 +827,9 @@ def get_dep_type(self): #Get possible dependency type (for intensity calc.) elif((self.ne > 1) and (self.nx > 1) and (self.ny > 1)): depType = 6 return depType + def copy(self): #is called from C++ + return deepcopy(self) + #**************************************************************************** class SRWLStokes(object): """Radiation Stokes Parameters""" @@ -1481,6 +1484,10 @@ def avg_update_interp_mutual(self, _more_stokes, _iter, _n_stokes_comp=4, _mult= #self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/(_iter + 1) self.arS[ir] = (self.arS[ir]*_iter + _mult*fInterp)/iter_p_1 + + #DEBUG + #print(' ir=',ir, 'arS[ir]=', self.arS[ir]) + ir += 1 else: #OC04052018 #self.arS[ir] = self.arS[ir]*iter_d_iter_p_1; ir += 1 @@ -1554,6 +1561,9 @@ def to_deg_coh(self, _rel_zer_tol=1.e-04, _rot=True): #05052018 ofstIc = orig_iec*origPerEp + orig_iec*origPerE + orig_ixc*origPerXp + orig_ixc*origPerX + orig_iyc*origPerYp + orig_iyc*origPerY absZerTolI = abs(self.arS[ofstIc])*_rel_zer_tol + #DEBUG + #print(' _rel_zer_tol=', _rel_zer_tol, ' absZerTolI=', absZerTolI) + auxNp = origNe*origNx*origNy auxNp *= auxNp resDegCohNonRot = array('f', [0]*auxNp) @@ -1606,7 +1616,13 @@ def to_deg_coh(self, _rel_zer_tol=1.e-04, _rot=True): #05052018 absMI = sqrt(reMI*reMI + imMI*imMI) reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] - resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + + denom = sqrt(reI1*reI2) + absZerTolI #OC31072018 + if(denom == 0): resDegCohNonRot[resOfst] = 0 + else: resDegCohNonRot[resOfst] = absMI/denom + + #resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + resOfst += 1 else: ofstMI = ix2_0_origPerXp_p_ix1_0_origPerX + iy2_0_origPerYp_p_iy1_0_origPerY @@ -1617,7 +1633,13 @@ def to_deg_coh(self, _rel_zer_tol=1.e-04, _rot=True): #05052018 absMI = sqrt(reMI*reMI + imMI*imMI) reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] - resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + + denom = sqrt(reI1*reI2) + absZerTolI #OC31072018 + if(denom == 0): resDegCohNonRot[resOfst] = 0 + else: resDegCohNonRot[resOfst] = absMI/denom + + #resDegCohNonRot[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + resOfst += 1 if(not _rot): return resDegCohNonRot @@ -2475,7 +2497,12 @@ def to_deg_coh_slow(self, _rel_zer_tol=1.e-04, _rot=True): #imI2 += (im_a000100 + (im_a000110 + im_a000101)*ry2)*rx2 + (im_a000010 + im_a000011*ry2)*ry2 + im_a000001*ry2 + im_a000000 #OC05052018: Note that this does not include all terms of multi-dim "bi-linear" interpolation!? - resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + denom = sqrt(reI1*reI2) + absZerTolI #OC31072018 + if(denom == 0): resDegCoh[resOfst] = 0 + else: esDegCoh[resOfst] = absMI/denom + + #resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + else: resDegCoh[resOfst] = 0 else: @@ -2495,7 +2522,12 @@ def to_deg_coh_slow(self, _rel_zer_tol=1.e-04, _rot=True): absMI = sqrt(reMI*reMI + imMI*imMI) reI1 = self.arS[ofstI1]#; imI1 = self.arS[ofstI1 + 1] reI2 = self.arS[ofstI2]#; imI2 = self.arS[ofstI2 + 1] - resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) + + denom = sqrt(reI1*reI2) + absZerTolI #OC31072018 + if(denom == 0): resDegCoh[resOfst] = 0 + else: resDegCoh[resOfst] = absMI/denom + + #resDegCoh[resOfst] = absMI/(sqrt(reI1*reI2) + absZerTolI) resOfst += 1 resEp += resEstep @@ -3182,7 +3214,16 @@ def __init__(self, _nx=1, _ny=1, _rx=1e-03, _ry=1e-03, _arTr=None, _extTr=0, _Fx halfRangeX = 0.5*_rx; halfRangeY = 0.5*_ry; - self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _x - halfRangeX, _x + halfRangeX, _nx, _y - halfRangeY, _y + halfRangeY, _ny) + + if(not hasattr(self, 'mesh')): #OC10112018 + self.mesh = SRWLRadMesh(_eStart, _eFin, _ne, _x - halfRangeX, _x + halfRangeX, _nx, _y - halfRangeY, _y + halfRangeY, _ny) + else: + self.mesh.eStart = _eStart + self.mesh.eFin = _eFin + self.mesh.xStart = _x - halfRangeX + self.mesh.xFin = _x + halfRangeX + self.mesh.yStart = _y - halfRangeY + self.mesh.yFin = _y + halfRangeY self.extTr = _extTr #0- transmission outside the grid/mesh is zero; 1- it is same as on boundary self.Fx = _Fx #estimated focal lengths [m] @@ -3330,18 +3371,20 @@ def set_reflect(self, _refl=1, _n_ph_en=1, _n_ang=1, _n_comp=1, _ph_en_start=0, _n_comp = int(_n_comp) if((_n_comp < 1) or (_n_comp > 2)): raise Exception("Number of reflectivity coefficient components can be 1 or 2") - - if(not(isinstance(_refl, list) or isinstance(_refl, array))): - self.arRefl = array('d', [_refl]*nTot) - for i in range(int(round(nTot/2))): - i2 = i*2 - self.arRefl[i2] = _refl - self.arRefl[i2 + 1] = 0 - else: - self.arRefl = _refl + + self.arRefl = None #OC12082018 + if((_refl is not None) and (_refl != 1)): #OC12082018 + if(not(isinstance(_refl, list) or isinstance(_refl, array))): + self.arRefl = array('d', [_refl]*nTot) + for i in range(int(round(nTot/2))): + i2 = i*2 + self.arRefl[i2] = _refl + self.arRefl[i2 + 1] = 0 + else: + self.arRefl = _refl #DEBUG - #print(self.arRefl) + #print('Reflection:', _refl, self.arRefl) self.reflNumPhEn = int(_n_ph_en) self.reflNumAng = int(_n_ang) @@ -4529,7 +4572,7 @@ def srwl_opt_setup_surf_height_1d(_height_prof_data, _dim, _ang, _ang_r=0, _amp_ hApprox = 0 ipStart = 0 - #OCTEST + #DEBUG #print('Heigh profile: nx=', auxMesh.nx, ' ny=', auxMesh.ny) #if('y' in _dim): @@ -4659,7 +4702,7 @@ def srwl_opt_setup_surf_height_1d_old(_height_prof_data, _dim, _ang, _ang_r=0, _ hApprox = 0 ipStart = 0 - #OCTEST + #DEBUG #print('Heigh profile: nx=', auxMesh.nx, ' ny=', auxMesh.ny) #for iy in range(optSlopeErr.ny): @@ -5393,6 +5436,8 @@ def srwl_uti_read_data_cols(_file_path, _str_sep, _i_col_start=0, _i_col_end=-1, for i in range(nRows): curLine = lines[_n_line_skip + i] + #print(curLine) + curLineParts = curLine.split(_str_sep) curNumParts = len(curLineParts) #print(curLineParts) @@ -5604,6 +5649,8 @@ def srwl_uti_read_mag_fld_3d(_fpath, _scom='#'): #(to walk-around the problem that simple allocation "array(type, [0]*n)" at large n is usually very time-consuming) def srwl_uti_array_alloc(_type, _n): nPartMax = 10000000 #to tune + #print('srwl_uti_array_alloc: array requested:', _n) + if(_n <= nPartMax): return array(_type, [0]*_n) #resAr = array(_type, [0]*_n) #print('Array requested:', _n, 'Allocated:', len(resAr)) @@ -5689,6 +5736,10 @@ def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0 resIntVsZXY = None if(_do3d): resIntVsZXY = array('f', [0]*(nzp1*_nx*_ny)) #array to store the final intensity + #OC19102018 + resFWHMxVsZ = array('f', [0]*nzp1) + resFWHMyVsZ = array('f', [0]*nzp1) + ec = _wfr.mesh.eStart if(_wfr.mesh.ne > 1): ec = 0.5*(_wfr.mesh.eStart + _wfr.mesh.eFin) @@ -5709,7 +5760,17 @@ def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0 yStart = _yc - halfRy yFin = _yc + halfRy yStep = (yFin - yStart)/(_ny - 1) if _ny > 1 else 0 - + + #OC19102018 + meshFWHMx = copy(_wfr.mesh) + meshFWHMx.ne = 1; meshFWHMx.ny = 1 + meshFWHMx.eStart = ec; meshFWHMx.eFin = ec + meshFWHMx.yStart = _yc; meshFWHMx.yFin = _yc + meshFWHMy = copy(_wfr.mesh) + meshFWHMy.ne = 1; meshFWHMy.nx = 1 + meshFWHMy.eStart = ec; meshFWHMy.eFin = ec + meshFWHMy.xStart = _xc; meshFWHMy.xFin = _xc + for iz in range(0, nzp1): if(iz > 0): @@ -5721,11 +5782,17 @@ def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0 curMesh = _wfr.mesh xStepCurMesh = (curMesh.xFin - curMesh.xStart)/(curMesh.nx - 1) yStepCurMesh = (curMesh.yFin - curMesh.yStart)/(curMesh.ny - 1) - curIntVsX = array('f', [0]*_wfr.mesh.nx) - curIntVsY = array('f', [0]*_wfr.mesh.ny) + curIntVsX = array('f', [0]*curMesh.nx) + curIntVsY = array('f', [0]*curMesh.ny) srwl.CalcIntFromElecField(curIntVsX, _wfr, _pol, _type, 1, ec, _xc, _yc) #int. vs X + #OC19102018 + meshFWHMx.nx = curMesh.nx; meshFWHMx.xStart = curMesh.xStart; meshFWHMx.xFin = curMesh.xFin + intInfX = srwl.UtiIntInf(curIntVsX, meshFWHMx) + #print(intInfX) + resFWHMxVsZ[iz] = intInfX[4] + x = xStart for ix in range(_nx): #interpolation resIntVsZX[iz + ix*nzp1] = uti_math.interp_1d(x, curMesh.xStart, xStepCurMesh, curMesh.nx, curIntVsX, _ord_interp) @@ -5733,6 +5800,12 @@ def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0 srwl.CalcIntFromElecField(curIntVsY, _wfr, _pol, _type, 2, ec, _xc, _yc) #int. vs Y + #OC19102018 + meshFWHMy.ny = curMesh.ny; meshFWHMy.yStart = curMesh.yStart; meshFWHMy.yFin = curMesh.yFin + intInfY = srwl.UtiIntInf(curIntVsY, meshFWHMy) + #print(intInfY) + resFWHMyVsZ[iz] = intInfY[4] + y = yStart for iy in range(_ny): #interpolation resIntVsZY[iz + iy*nzp1] = uti_math.interp_1d(y, curMesh.yStart, yStepCurMesh, curMesh.ny, curIntVsY, _ord_interp) @@ -5755,7 +5828,8 @@ def srwl_wfr_prop_drifts(_wfr, _dz, _nz, _pp, _do3d=False, _nx=-1, _ny=-1, _rx=0 resMesh.zFin = _dz*_nz #adding long. mesh params (note: these may not propagate further!) resMesh.nz = nzp1 #adding long. mesh params (may not propagate further!) - return resIntVsZX, resIntVsZY, resIntVsZXY, resMesh + #return resIntVsZX, resIntVsZY, resIntVsZXY, resMesh + return resIntVsZX, resIntVsZY, resIntVsZXY, resMesh, resFWHMxVsZ, resFWHMyVsZ #OC19102018 #**********************Auxiliary function to setup Coherent Wavefront from Intensity (assuming spherical or astigmatic wave) def srwl_wfr_from_intens(_ar_int, _mesh, _part_beam, _Rx, _Ry, _xc=0, _yc=0): @@ -5833,7 +5907,7 @@ def srwl_wfr_from_intens(_ar_int, _mesh, _part_beam, _Rx, _Ry, _xc=0, _yc=0): wfr.avgPhotEn = _mesh.eStart if(_mesh.ne == 1) else 0.5*(_mesh.eStart + _mesh.eFin) #average photon energy for time-domain simulations wfr.presCA = 0 #presentation/domain: 0- coordinates, 1- angles wfr.presFT = 0 #presentation/domain: 0- frequency (photon energy), 1- time - wfr.unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) ? + wfr.unitElFld = 1 #electric field units: 0- arbitrary, 1- sqrt(Phot/s/0.1%bw/mm^2), 2- sqrt(J/eV/mm^2) or sqrt(W/mm^2), depending on representation (freq. or time) #wfr.arElecPropMatr = array('d', [0] * 20) #effective 1st order "propagation matrix" for electron beam parameters #wfr.arMomX = array('d', [0] * 11 * _ne) #statistical moments (of Wigner distribution); to check the exact number of moments required #wfr.arMomY = array('d', [0] * 11 * _ne) @@ -5849,7 +5923,8 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #_rand_meth=1, _tryToUseMPI=True, _wr=0.): #OC07092016 (renamed _wr) #_rand_meth=1, _tryToUseMPI=True, _wr=0., _det=None): #OC06122016 #_rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None): #OC05012017 - _rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None, _me_approx=0): #OC05042017 + #_rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None, _me_approx=0): #OC05042017 + _rand_meth=1, _tryToUseMPI=True, _wr=0., _wre=0., _det=None, _me_approx=0, _file_bkp=False): #OC14082018 """ Calculate Stokes Parameters of Emitted (and Propagated, if beamline is defined) Partially-Coherent SR :param _e_beam: Finite-Emittance e-beam (SRWLPartBeam type) @@ -5885,6 +5960,7 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ :param _wre: initial wavefront radius error [m] to assume at wavefront propagation (is taken into account if != 0) :param _det: detector object for post-processing of final intensity (instance of SRWLDet) :param _me_approx: approximation to be used at multi-electron integration: 0- none (i.e. do standard M-C integration over 5D phase space volume of e-beam), 1- integrate numerically only over e-beam energy spread and use convolution to treat transverse emittance + :param _file_bkp: create or not backup files with resulting multi-electron radiation characteristics """ doMutual = 0 #OC30052017 @@ -5901,6 +5977,7 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #DEBUG #self.arOpt = [] #self.arProp = [] + #print('_file_bkp=',_file_bkp) nProc = 1 rank = 1 @@ -6294,6 +6371,8 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ if(_opt_bl is None): arPrecParSR[6] = 0 #Ensure non-automatic choice of numbers of points if there is no beamline + bkpFileToBeSaved = False #OC14082018 + if((rank > 0) or (nProc == 1)): #if((nProc > 1) and (_opt_bl != None)): #receive mesh for the resulting wavefront from the master @@ -6361,10 +6440,13 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ randAr = array('d', [0]*6) #for random Gaussian numbers - #random.seed(rank) + #random.seed(rank) #old + random.seed(rank*123) newSeed = random.randint(0, 1000000) random.seed(newSeed) + + #random.seed(1) #DEBUG iAuxSendCount = 0 #for debug @@ -6588,24 +6670,9 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #print('zStart=', wfr.mesh.zStart) #END DEBUG - #DEBUG - #if(i == 48): - # print('Eel=', wfr.partBeam.partStatMom1.get_E(), ' GeV') - # print('xe=', wfr.partBeam.partStatMom1.x, ' xpe=', wfr.partBeam.partStatMom1.xp, ' ye=', wfr.partBeam.partStatMom1.y, ' ype=', wfr.partBeam.partStatMom1.yp) - # print('nx=', wfr.mesh.nx, ' xStart=', wfr.mesh.xStart, ' xFin=', wfr.mesh.xFin) - # print('ny=', wfr.mesh.ny, ' yStart=', wfr.mesh.yStart, ' yFin=', wfr.mesh.yFin) - #END DEBUG - srwl.CalcElecFieldSR(wfr, 0, _mag, arPrecParSR) #calculate Electric Field emitted by current electron if(wfr2 is not None): srwl.CalcElecFieldSR(wfr2, 0, _mag, arPrecParSR) #OC30052017 - #DEBUG - #if(i == 48): - # arI1 = array('f', [0]*wfr.mesh.nx*wfr.mesh.ny) #"flat" 2D array to take intensity data - # srwl.CalcIntFromElecField(arI1, wfr, 6, 0, 3, wfr.mesh.eStart, 0, 0) - # srwl_uti_save_intens_ascii(arI1, wfr.mesh, os.path.join(os.getcwd(), 'data_CDI', 'debug_int_se.dat')) - #END DEBUG - #print('completed (lasted', round(time.time() - t0, 6), 's)') #DEBUG #print('DEBUG: Commented-out: CalcElecFieldSR') #print('DEBUG MESSAGE: CalcElecFieldSR called (rank:', rank,')') @@ -6889,29 +6956,51 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _mutual = doMutual) #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC26042016 #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + + fp = _file_path; fp1 = file_path1; fp2 = file_path2; fpdc1 = file_path_deg_coh1; fpdc2 = file_path_deg_coh2 #OC14082018 + if(_file_bkp): + if(bkpFileToBeSaved): + if(fp is not None): fp = copy(fp) + '.bkp' + if(fp1 is not None): fp1 = copy(fp1) + '.bkp' + if(fp2 is not None): fp2 = copy(fp2) + '.bkp' + if(fpdc1 is not None): fpdc1 = copy(fpdc1) + '.bkp' + if(fpdc2 is not None): fpdc2 = copy(fpdc2) + '.bkp' + bkpFileToBeSaved = False + else: bkpFileToBeSaved = True if(_char == 40): #OC03052018 - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) #OC14082018 if(resStokes2 is not None): #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) - srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 - srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, fp1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, fpdc1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 if(resStokes3 is not None): #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) - srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 - srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC06052018 + srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, fp2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, fpdc2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 elif(_char == 4): #OC03052018 #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 - srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC06052018 + srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, fpdc1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) - srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 - srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) #OC06052018 + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, fp2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) #OC06052018 + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, fpdc2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) #OC14082018 else: - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 - srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, fp2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 #DEBUG #srwl_uti_save_intens_ascii(workStokes.arS, workStokes.mesh, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) @@ -7003,10 +7092,10 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #if((_char == 4) and (workStokes2 is not None)): #OC30052017 #Cuts of Mutual Intensity vs X & Y # comMPI.Recv([workStokes2.arS, MPI.FLOAT], source=MPI.ANY_SOURCE) #receive + #OC15102018 (moved this log-writing to the place where other files are saved) #MR20160907 #Save .log and .json files: - particle_number = (i + 1) * _n_part_avg_proc - #srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles) - srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles, filename=log_path) + #particle_number = (i + 1) * _n_part_avg_proc + #srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles, filename=log_path) #DEBUG #srwl_uti_save_text("Received intensity # " + str(i), _file_path + ".er.dbg") @@ -7050,28 +7139,55 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC26042016 #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 + #OC15102018 (moved this log-writing to the place where other files are saved): + #MR20160907 #Save .log and .json files: + particle_number = (i + 1) * _n_part_avg_proc + srwl_uti_save_stat_wfr_emit_prop_multi_e(particle_number, total_num_of_particles, filename=log_path) + + fp = _file_path; fp1 = file_path1; fp2 = file_path2; fpdc1 = file_path_deg_coh1; fpdc2 = file_path_deg_coh2 #OC14082018 + if(_file_bkp): + if(bkpFileToBeSaved): + if(fp is not None): fp = copy(fp) + '.bkp' + if(fp1 is not None): fp1 = copy(fp1) + '.bkp' + if(fp2 is not None): fp2 = copy(fp2) + '.bkp' + if(fpdc1 is not None): fpdc1 = copy(fpdc1) + '.bkp' + if(fpdc2 is not None): fpdc2 = copy(fpdc2) + '.bkp' + bkpFileToBeSaved = False + else: bkpFileToBeSaved = True + if(_char == 40): #OC03052018 - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 0) #OC14082018 if(resStokes2 is not None): #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) - srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 - srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + #srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, file_path1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 + srwl_uti_save_intens_ascii(resStokes2.arS, resStokes2.mesh, fp1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), resStokes2.mesh, fpdc1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 if(resStokes3 is not None): #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) - srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 - srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + #srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, file_path2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC060502018 + srwl_uti_save_intens_ascii(resStokes3.arS, resStokes3.mesh, fp2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 1) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + srwl_uti_save_intens_ascii(resStokes3.to_deg_coh(), resStokes3.mesh, fpdc2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 elif(_char == 4): #OC03052018 #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSaveMutualHorCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 - srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, file_path_deg_coh1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) + srwl_uti_save_intens_ascii(resStokes.to_deg_coh(), meshRes, fpdc1, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = 1, _cmplx = 0) #OC14082018 if((resStokes2 is not None) and (meshRes2 is not None)): #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSaveMutualVerCut, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) - srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 - srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC060502018 + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, fp2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 + #srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, file_path_deg_coh2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) + srwl_uti_save_intens_ascii(resStokes2.to_deg_coh(), meshRes2, fpdc2, _n_stokes = 1, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = 0) #OC14082018 else: - srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC30052017 + #srwl_uti_save_intens_ascii(resStokes.arS, meshRes, file_path1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC30052017 + srwl_uti_save_intens_ascii(resStokes.arS, meshRes, fp1, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 if((resStokes2 is not None) and (meshRes2 is not None)): #OC30052017 - srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + #srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, file_path2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) + srwl_uti_save_intens_ascii(resStokes2.arS, meshRes2, fp2, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual, _cmplx = (1 if doMutual else 0)) #OC14082018 #DEBUG #srwl_uti_save_intens_ascii(workStokes.arS, meshRes, _file_path, numComp, _arLabels = resLabelsToSave, _arUnits = resUnitsToSave, _mutual = doMutual) #OC16012017 @@ -7282,6 +7398,7 @@ def srwl_wfr_emit_prop_multi_e(_e_beam, _mag, _mesh, _sr_meth, _sr_rel_prec, _n_ =5 -Re(E): Real part of Single-Electron Electric Field; =6 -Im(E): Imaginary part of Single-Electron Electric Field; =7 -"Single-Electron" Intensity, integrated over Time or Photon Energy (i.e. Fluence) + =8 -"Single-Electron" Mutual Intensity (i.e. E(r)E*(r')) :param _inDepType: input switch specifying type of dependence to be extracted: =0 -vs e (photon energy or time); =1 -vs x (horizontal position or angle); diff --git a/env/work/srw_python/srwlpy.pyd b/env/work/srw_python/srwlpy.pyd index 36c05bef..12935411 100644 Binary files a/env/work/srw_python/srwlpy.pyd and b/env/work/srw_python/srwlpy.pyd differ diff --git a/env/work/srw_python/srwlpy.so b/env/work/srw_python/srwlpy.so index 2e06874e..2fe8eef4 100644 Binary files a/env/work/srw_python/srwlpy.so and b/env/work/srw_python/srwlpy.so differ diff --git a/env/work/srw_python/uti_io.py b/env/work/srw_python/uti_io.py index e1926470..8dc9a029 100644 --- a/env/work/srw_python/uti_io.py +++ b/env/work/srw_python/uti_io.py @@ -124,6 +124,9 @@ def read_image(image_path): # MR26102017 except: raise ImportError(msg.format('pillow')) + #OC11112018 (as suggested by Rafael Celestre, to walk around image size limit) + Image.MAX_IMAGE_PIXELS = None + # Read the image: raw_image = Image.open(image_path) image_format = raw_image.format