├── .flake8 ├── .gitattributes ├── .gitconfig ├── .github └── workflows │ ├── notebook-check.yml │ └── tests.yml ├── .gitignore ├── .readthedocs.yaml ├── .vscode └── settings.json ├── AUTHORS.rst ├── CITATION.cff ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── NEW.rst ├── Pipfile ├── Pipfile.lock ├── README.rst ├── REFERENCES.rst ├── RESULTS.rst ├── STATISTICS.rst ├── TODO.rst ├── axicon_result.png ├── bitbucket-pipelines.yml ├── creating_video.mp4 ├── deactivate ├── diffractio ├── __init__.py ├── config.py ├── deprecated │ ├── _deprecated drawings XYZ.py │ ├── _deprecated.py │ └── _utils_slicer.py ├── diffractio.py ├── other │ ├── count_number_lines.py │ ├── functions.rst │ └── get_functions.py ├── scalar_fields_X.py ├── scalar_fields_XY.py ├── scalar_fields_XYZ.py ├── scalar_fields_XZ.py ├── scalar_fields_Z.py ├── scalar_masks_X.py ├── scalar_masks_XY.py ├── scalar_masks_XYZ.py ├── scalar_masks_XZ.py ├── scalar_sources_X.py ├── scalar_sources_XY.py ├── utils_common.py ├── utils_drawing.py ├── utils_drawing3D.py ├── utils_dxf.py ├── utils_math.py ├── utils_multiprocessing.py ├── utils_optics.py ├── utils_tests.py ├── utils_typing.py ├── vector_fields_X.py ├── vector_fields_XY.py ├── vector_fields_XYZ.py ├── vector_fields_XZ.py ├── vector_fields_Z.py ├── vector_masks_XY.py └── vector_sources_XY.py ├── docs ├── Makefile ├── _static ├── authors.rst ├── conf.py ├── contributing.rst ├── diffractio.rst ├── examples_scalar.rst ├── examples_vector.rst ├── files_jupyter.rst ├── files_python.rst ├── functioning.rst ├── functions.rst ├── history.rst ├── index.rst ├── installation.rst ├── logo.png ├── logoUCM.png ├── make.bat ├── modules.rst ├── new.rst ├── readme.rst ├── readme1.png ├── readme10.png ├── readme2.png ├── readme3.png ├── readme4.png ├── readme5.png ├── readme6.png ├── readme7.png ├── readme8.png ├── readme9.png ├── references.rst ├── requirements.txt ├── results.rst ├── source │ ├── README.txt │ ├── examples_scalar │ │ ├── USAF-1951-1024.png │ │ ├── arago_point.ipynb │ │ ├── blazed_grating.ipynb │ │ ├── dammann.ipynb │ │ ├── diffraction_objects.ipynb │ │ ├── diffraction_slit.ipynb │ │ ├── double_grating.ipynb │ │ ├── far_near_field.ipynb │ │ ├── fig1.png │ │ ├── focal_shift.ipynb │ │ ├── fresnel_biprism.ipynb │ │ ├── fresnel_lens.ipynb │ │ ├── gauss_beam.ipynb │ │ ├── image_formation.ipynb │ │ ├── lenaColor.png │ │ ├── lenses.ipynb │ │ ├── photon_sieve.ipynb │ │ ├── qt.png │ │ ├── reflection_refraction.ipynb │ │ ├── scattering_small_cylinders.ipynb │ │ ├── talbot_effect.ipynb │ │ └── variable_refractive_index.ipynb │ ├── examples_vector │ │ ├── SLM.ipynb │ │ ├── VRS_paper.ipynb │ │ ├── calibration_slm_jones_2500.npz │ │ ├── diffraction_slit.ipynb │ │ ├── gauss_beam.ipynb │ │ ├── lens.ipynb │ │ ├── malus_law.ipynb │ │ ├── reflection_refraction.ipynb │ │ ├── vector FPZ.ipynb │ │ ├── vector grating xz.ipynb │ │ ├── vector_double_slit_experiment.ipynb │ │ └── vector_grating_xy.ipynb │ ├── functioning │ │ ├── WPM_ws.ipynb │ │ ├── add_fields.ipynb │ │ ├── artifacts_bpm.ipynb │ │ ├── backpropagation.ipynb │ │ ├── developing_new_functions.ipynb │ │ ├── dxf_XY.ipynb │ │ ├── dxf_XZ.ipynb │ │ ├── has_edges.ipynb │ │ ├── hatch_polyline.dxf │ │ ├── hatch_polyline2.dxf │ │ ├── multiprocessing.ipynb │ │ ├── oversampling_xy.ipynb │ │ ├── phase_intensity.ipynb │ │ ├── power_z_propagation.ipynb │ │ ├── qt2.png │ │ ├── quality_factor.ipynb │ │ └── surfaces.ipynb │ ├── tutorial_scalar │ │ ├── algorithms │ │ │ ├── BPM.ipynb │ │ │ ├── CZT.ipynb │ │ │ ├── FFT.ipynb │ │ │ ├── PWD.ipynb │ │ │ ├── RS.ipynb │ │ │ ├── WPM.ipynb │ │ │ └── tutorial.rst │ │ ├── comparison │ │ │ ├── CZT_vs_RS.ipynb │ │ │ ├── RS_vs_WPM.ipynb │ │ │ ├── WPM_vs_BPM.ipynb │ │ │ └── tutorial.rst │ │ ├── drawing │ │ │ ├── creating_video.ipynb │ │ │ ├── creating_video.mp4 │ │ │ ├── external_qt.ipynb │ │ │ ├── interactive.png │ │ │ ├── interactive2.png │ │ │ ├── interactive_in_diffractio.ipynb │ │ │ ├── logarithm.ipynb │ │ │ ├── qt_propagation.png │ │ │ ├── tutorial.rst │ │ │ ├── use_interact_visualize_profiles.ipynb │ │ │ └── video_circle.mp4 │ │ ├── other │ │ │ ├── fresnel_equations.ipynb │ │ │ └── tutorial.rst │ │ ├── scalar_X │ │ │ ├── masks_x.ipynb │ │ │ ├── profile1.txt │ │ │ ├── profile2.txt │ │ │ ├── save_load.hkl │ │ │ ├── save_load.npz │ │ │ ├── sources_x.ipynb │ │ │ ├── tutorial.rst │ │ │ └── tutorial_x.ipynb │ │ ├── scalar_XY │ │ │ ├── hatch_polyline.dxf │ │ │ ├── masks_xy.ipynb │ │ │ ├── masks_xy_procedures.ipynb │ │ │ ├── save_load.npz │ │ │ ├── sources_xy.ipynb │ │ │ ├── spain.png │ │ │ ├── tutorial.rst │ │ │ └── tutorial_xy.ipynb │ │ ├── scalar_XYZ │ │ │ ├── Meissner_Tetrahedron.stl │ │ │ ├── masks_xyz.ipynb │ │ │ ├── masks_xyz_procedures.ipynb │ │ │ ├── save_load_xyz.npz │ │ │ ├── tutorial.rst │ │ │ ├── tutorial_xyz.ipynb │ │ │ ├── video_RS_int.mp4 │ │ │ ├── wpm-bpm 3d.ipynb │ │ │ └── wpm_without_storing.ipynb │ │ ├── scalar_XZ │ │ │ ├── creating_video.mp4 │ │ │ ├── detection.png │ │ │ ├── drawing_xz.ipynb │ │ │ ├── hatch_polyline2.dxf │ │ │ ├── masks_xz.ipynb │ │ │ ├── masks_xz_procedures.ipynb │ │ │ ├── profile.png │ │ │ ├── profile1.txt │ │ │ ├── profile2.txt │ │ │ ├── qt3.png │ │ │ ├── save_load.hkl │ │ │ ├── save_load.npz │ │ │ ├── star_hole.png │ │ │ ├── tutorial.rst │ │ │ ├── tutorial_xz.ipynb │ │ │ ├── video_xz_int_long.avi │ │ │ ├── video_xz_int_trans.avi │ │ │ └── video_xz_pha_trans.avi │ │ └── scalar_Z │ │ │ ├── scalar_field_z.ipynb │ │ │ └── tutorial.rst │ └── tutorial_vector │ │ ├── algorithms │ │ ├── VCZT.ipynb │ │ ├── VFFT.ipynb │ │ ├── VRS.ipynb │ │ ├── comparison │ │ │ └── VCZT_vs_VRS.ipynb │ │ └── tutorial.rst │ │ ├── drawing │ │ └── tutorial.rst │ │ ├── vector_XY │ │ ├── calibration_slm_jones_2500.npz │ │ ├── tutorial.rst │ │ ├── tutorial_vector_XY.ipynb │ │ ├── tutorial_vector_XY_draw.ipynb │ │ ├── tutorial_vector_masks_XY.ipynb │ │ └── tutorial_vector_sources_XY.ipynb │ │ ├── vector_XYZ │ │ ├── tutorial.rst │ │ └── tutorial_vector_XYZ.ipynb │ │ └── vector_XZ │ │ ├── tutorial.rst │ │ └── tutorial_vector_XZ.ipynb ├── statistics.rst ├── todo.rst ├── tutorials_scalar.rst ├── tutorials_vector.rst ├── usage.rst ├── usage1.png ├── usage10.png ├── usage11.png ├── usage12.png ├── usage13.png ├── usage14.png ├── usage2.png ├── usage3.png ├── usage4.png ├── usage5.png ├── usage6.png ├── usage7.png ├── usage8.png ├── usage9.png ├── video_RS_int.mp4 └── xyz_RS.png ├── logo.png ├── logoUCM.png ├── pytest.ini ├── readthedocs.yaml ├── requirements.txt ├── requirements_dev.txt ├── setup.cfg ├── setup.py ├── test_jupyter └── test_Diffractio.ipynb ├── tests ├── __init__.py ├── _test_scalar_fields_XYZ.py ├── profile1.txt ├── profile2.txt ├── spain.png ├── star_hole.png ├── test_scalar_fields_X.py ├── test_scalar_fields_XY.py ├── test_scalar_fields_XZ.py ├── test_scalar_fields_X_multiprocessing.py ├── test_scalar_masks_X.py ├── test_scalar_masks_XY.py ├── test_scalar_masks_XYZ.py ├── test_scalar_masks_XZ.py ├── test_scalar_sources_X.py ├── test_scalar_sources_XY.py ├── test_utils_math.py ├── test_utils_multiprocessing.py ├── test_vector_draw_XY.py ├── test_vector_fields_XY.py ├── test_vector_masks_XY.py └── test_vector_sources_XY.py ├── tox.ini ├── usage1.png ├── usage10.png ├── usage2.png ├── usage3.png ├── usage4.png ├── usage5.png ├── usage6.png ├── usage7.png ├── usage8.png └── usage9.png /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = 3 | E501, W605, E226, W504, F401 4 | 5 | # Normal default 6 | # E121,E123,E126,E226,E24,E704,W503,W504, 7 | # Additional ignores: 8 | # E111, E114, E115, E116, E122, E124, E125, E127, E128, E129, E131, 9 | # E265, E266, 10 | # E305, E306, 11 | # E722, E741, 12 | # F401, F403, F811, F841, 13 | # Some new flake8 ignores: 14 | # N801, N802, N803, N806, N812, 15 | 16 | exclude = 17 | .git 18 | build 19 | # External files. 20 | versioneer.py 21 | tools/gh_api.py 22 | tools/github_stats.py 23 | .tox 24 | .eggs 25 | 26 | # per-file-ignores = 27 | # setup.py: E402 28 | # setupext.py: E501 29 | # 30 | # examples/widgets/rectangle_selector.py: E501 31 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.svg binary 2 | *.png binary 3 | *.pdf diff=pdf 4 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [diff "pdf"] 2 | textconv = pdfinfo 3 | 4 | 5 | 6 | [difftool "image_diff"] 7 | cmd = compare $REMOTE $LOCAL png:- | montage -geometry 400x -font Liberation-Sans -label "reference" $LOCAL -label "diff" - -label "current--%f" $REMOTE x: 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/notebook-check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Jupyter notebook build check 5 | 6 | env: 7 | NOTEBOOK_DIR: 'docs' 8 | EXECUTION_TIMEOUT: 10 9 | on: 10 | push: 11 | branches: [ "main" ] 12 | pull_request: 13 | branches: [ "main" ] 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | python-version: ["3.10"] 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | cache: 'pip' # caching pip dependencies 30 | # https://github.com/actions/setup-python?tab=readme-ov-file#caching-packages-dependencies 31 | - name: Install dependencies 32 | run: | 33 | python -m pip install --upgrade pip 34 | pip install . 35 | pip install jupyter papermill 36 | - name: Execute notebooks 37 | run: | 38 | notebooks=$(find "$NOTEBOOK_DIR" -name "*.ipynb") 39 | if [[ -n "$notebooks" ]]; then 40 | echo "Running notebooks:" 41 | find "$NOTEBOOK_DIR" -name "*.ipynb" -print0 | while read -r -d $'\0' notebook_path; 42 | do 43 | echo "[notebook_path] $notebook_path" 44 | # Execute notebooks using papermill and silence output 45 | python -m papermill "$notebook_path" /dev/null \ 46 | --execution-timeout "$EXECUTION_TIMEOUT" \ 47 | --no-request-save-on-cell-execute --autosave-cell-every 0 48 | # --no-progress-bar 49 | done 50 | else 51 | echo "No Jupyter notebooks found in the 'docs' directory." 52 | fi 53 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Test Python package 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | python-version: ["3.10", "3.11", "3.12"] 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | cache: 'pip' # caching pip dependencies 27 | # https://github.com/actions/setup-python?tab=readme-ov-file#caching-packages-dependencies 28 | - name: Install dependencies 29 | run: | 30 | python -m pip install --upgrade pip 31 | if [ -f requirements_dev.txt ]; then pip install -r requirements_dev.txt; fi 32 | pip install . 33 | - name: Test with pytest 34 | run: | 35 | mkdir -p test-reports 36 | # https://stackoverflow.com/a/1221844/7346915 37 | mkfifo pipe 38 | tee pytest-coverage.txt < pipe & 39 | echo $? 40 | py.test --junitxml=test-reports/test-report.xml --cov-report=term-missing:skip-covered --cov=diffractio > pipe 41 | 42 | - name: Pytest coverage comment 43 | uses: MishaKav/pytest-coverage-comment@v1.1.51 44 | if: always() 45 | with: 46 | pytest-coverage-path: ./pytest-coverage.txt 47 | junitxml-path: ./test-reports/test-report.xml 48 | 49 | - name: Publish Test Results 50 | uses: EnricoMi/publish-unit-test-result-action@v2 51 | if: always() 52 | with: 53 | files: | 54 | test-reports/**/*.xml 55 | test-reports/**/*.trx 56 | test-reports/**/*.json 57 | 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Add any directories, files, or patterns you don't want to be tracked by version control 2 | 3 | # Compiled python modules. 4 | *.pyc 5 | 6 | # Temporal files 7 | *~ 8 | 9 | 10 | # Byte-compiled / optimized / DLL files 11 | __pycache__/ 12 | *.py[cod] 13 | *$py.class 14 | 15 | # C extensions 16 | *.so 17 | 18 | # Checkpoints 19 | *checkpoint.ipynb 20 | .ipynb_checkpoints/ 21 | 22 | # Tests 23 | test_results/ 24 | 25 | # Visual studio 26 | .vscode/* 27 | 28 | # Distribution / packaging 29 | .Python 30 | docs/_build/ 31 | env/ 32 | build/ 33 | develop-eggs/ 34 | dist/ 35 | downloads/ 36 | eggs/ 37 | .eggs/ 38 | *.egg 39 | *.egg-info/ 40 | lib/ 41 | lib64/ 42 | parts/ 43 | sdist/ 44 | var/ 45 | distLM/ 46 | .installed.cfg 47 | 48 | 49 | # PyInstaller 50 | # Usually these files are written by a python script from a template 51 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 52 | *.manifest 53 | *.spec 54 | 55 | # Installer logs 56 | pip-log.txt 57 | pip-delete-this-directory.txt 58 | 59 | # Unit test / coverage reports 60 | htmlcov/ 61 | .tox/ 62 | .coverage 63 | .coverage.* 64 | .cache 65 | nosetests.xml 66 | coverage.xml 67 | *,cover 68 | .hypothesis/ 69 | 70 | # Translations 71 | *.mo 72 | *.pot 73 | 74 | # Django stuff: 75 | *.log 76 | 77 | # Sphinx documentation 78 | # docs/_build/ 79 | 80 | # PyBuilder 81 | target/ 82 | 83 | # pyenv python configuration file 84 | .python- 85 | .env 86 | 87 | tests_results*/ 88 | 89 | htmlcov/ -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.10" 12 | # You can also specify other tool versions: 13 | # nodejs: "20" 14 | # rust: "1.70" 15 | # golang: "1.20" 16 | 17 | # Build documentation in the "docs/" directory with Sphinx 18 | sphinx: 19 | configuration: docs/conf.py 20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 21 | # builder: "dirhtml" 22 | # Fail on all warnings to avoid broken references 23 | # fail_on_warning: true 24 | 25 | # Optionally build your docs in additional formats such as PDF and ePub 26 | # formats: 27 | # - pdf 28 | # - epub 29 | 30 | # Optional but recommended, declare the Python requirements required 31 | # to build your documentation 32 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 33 | python: 34 | install: 35 | - requirements: docs/requirements.txt 36 | - method: pip 37 | path: . -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.testing.unittestEnabled": false, 3 | "python.testing.pytestEnabled": true, 4 | "python.analysis.typeCheckingMode": "basic", 5 | "python.defaultInterpreterPath": "./.env/bin/python" 6 | } -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Credits 3 | =========== 4 | 5 | Development Lead 6 | --------------------------- 7 | 8 | * Luis Miguel Sanchez Brea 9 | 10 | 11 | **Universidad Complutense de Madrid**, 12 | Faculty of Physical Sciences, 13 | Department of Optics 14 | Plaza de las ciencias 1, 15 | ES-28040 Madrid (Spain) 16 | 17 | 18 | Contributors 19 | -------------- 20 | 21 | * Ángela Soria Garcia 22 | 23 | * Jesús del Hoyo Muñoz 24 | 25 | * Francisco Javier Torcal-Milla 26 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 0.3.1 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: Sanchez-Brea 5 | given-names: Luis Miguel 6 | orcid: https://orcid.org/0000-0003-1337-969X 7 | title: "Diffractio" 8 | version: 0.3.1 9 | identifiers: 10 | - type: doi 11 | value: 10.1117/12.3021879 12 | date-released: 2019-01-01 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every little bit 8 | helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/optbrea/diffractio/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the Github issues for bugs. Anything tagged with "bug" and "help 30 | wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the Github issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | Python diffraction and interference could always use more documentation, whether as part of the 42 | official Python diffraction and interference docs, in docstrings, or even on the web in blog posts, 43 | articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at https://github.com/optbrea/diffractio/issues. 49 | 50 | If you are proposing a feature: 51 | 52 | * Explain in detail how it would work. 53 | * Keep the scope as narrow as possible, to make it easier to implement. 54 | * Remember that this is a volunteer-driven project, and that contributions are welcome :) 55 | 56 | Get Started! 57 | ------------ 58 | 59 | Ready to contribute? Here's how to set up `diffractio` for local development. 60 | 61 | 1. Fork the `diffractio` repo on Github. 62 | 2. Clone your fork locally:: 63 | 64 | $ git clone git@github.com:optbrea/diffractio.git 65 | 66 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 67 | 68 | $ mkvirtualenv diffractio 69 | $ cd diffractio/ 70 | $ python setup.py develop 71 | 72 | 4. Create a branch for local development:: 73 | 74 | $ git checkout -b name-of-your-bugfix-or-feature 75 | 76 | Now you can make your changes locally. 77 | 78 | 5. When you're done making changes, check that your changes pass flake8 and the 79 | tests, including testing other Python versions with tox:: 80 | 81 | $ flake8 diffractio tests 82 | $ python setup.py test or py.test 83 | $ tox 84 | 85 | To get flake8 and tox, just pip install them into your virtualenv. 86 | 87 | 6. Commit your changes and push your branch to GitHub:: 88 | 89 | $ git add . 90 | $ git commit -m "Your detailed description of your changes." 91 | $ git push origin name-of-your-bugfix-or-feature 92 | 93 | 7. Submit a pull request through the Github website. 94 | 95 | Pull Request Guidelines 96 | ----------------------------- 97 | 98 | Before you submit a pull request, check that it meets these guidelines: 99 | 100 | 1. The pull request should include tests. 101 | 2. If the pull request adds functionality, the docs should be updated. Put 102 | your new functionality into a function with a docstring, and add the 103 | feature to the list in README.rst. 104 | 3. The pull request should work for Python 3.10, and for PyPy. Check 105 | https://travis-ci.org/optbrea/diffractio/pull_requests 106 | and make sure that the tests pass for all supported Python versions. 107 | 108 | Tips 109 | ---- 110 | 111 | To run a subset of tests:: 112 | 113 | $ py.test tests.test_diffractio 114 | 115 | 116 | Deploying 117 | --------- 118 | 119 | A reminder for the maintainers on how to deploy. 120 | Make sure all your changes are committed (including an entry in HISTORY.rst). 121 | Then run:: 122 | 123 | $ bumpversion patch # possible: major / minor / patch 124 | $ git push 125 | $ git push --tags 126 | 127 | Travis will then deploy to PyPI if tests pass. 128 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 6 | 0.3.1 7 | -------------------------------- 8 | Beta state 9 | 10 | - Package has been moved to github: https://github.com/optbrea/diffractio/ 11 | 12 | 13 | * Improvements: 14 | 15 | - new fresnel_equations_kx, fresnel_equations, transmitances_reflectances_kx, transmitances_reflectances functions. 16 | 17 | - Pyvista has been implemented for 3D visualization. 18 | 19 | - 'check_none' function (utils_common) has been implemented to check if a variable is None. 20 | 21 | - 'add function' (utils_common, and scalar_fields) has been modified to take into consideration different procedures for adding sources or masks. 22 | 23 | - 'oversampling function' has been implemented to increase the resolution of the masks (utils_common, and Scalar X, XY, XYZ, XZ, Z). This is also performed with the cut_resample function. However, this function oversamples with integer factors. 24 | 25 | - FP_WPM for vector XZ and XYZ fields has been implemented. 26 | 27 | - Implementation of scalar (intensity, phase, amplitude) and vector (irradiance, energy_density, etc) parameters in get function. 28 | 29 | - new module diffractio.py to import all the frames: u = Diffractio('scalar', 'source', x=x, wavelength=0.6328*um) produced the same as u=Scalar_source_X(x=x, wavelength=0.6328*um) 30 | 31 | 32 | 33 | * Fix bugs: 34 | 35 | - new definition of X mask: fresnel_lens 36 | 37 | - ndgrid -> meshgrid (this produced a lot of minor bugs) 38 | 39 | - bug in scalar_x field: kernelRSinverse and CZT when z<0. (bakcward propagation). 40 | 41 | 42 | * Refactoring: 43 | 44 | - refraction_index -> refractive_index ... in all words. 45 | 46 | - XZ masks: sphere -> cylinder. 47 | semi-sphere -> semi-cylinder. 48 | square -> rectangle, 49 | 50 | 51 | * New features: 52 | 53 | - XY masks: edge_rough, slit_rough, double_slit_rough, squares_nxm 54 | 55 | - XY masks: .dxf method for loading masks from .dxf files. 56 | 57 | - XZ masks: .dxf method for loading masks from .dxf files. 58 | 59 | - XZ masks: insert_array_masks, aspheric_lens, lens 60 | 61 | - XZ masks: New refractive_index_from_scalar_mask_XY method. 62 | 63 | - XYZ masks: .stl method for loading 3D masks from .stl files. 64 | 65 | - has_edges parameters in WPM and BPM methods can be an array masking in desired z positions. 66 | 67 | - vector XZ fields: FPWPM algorithm has been implemented for vector propagation. 68 | 69 | - vector XYZ fields: FPWPM algorithm has been implemented for vector propagation. 70 | 71 | - vector XY mask: q_plate, SLM, radial_polarizer, azimuthal_polarizer, RCP, LCP, RCP2LCP, LCP2 RCP. 72 | 73 | 74 | * Documentation: 75 | 76 | - New pages for the new features. 77 | 78 | - Changed citing reference to SPIE article: Luis Miguel Sanchez-Brea, Angela Soria-Garcia, Joaquin Andres-Porras, Veronica Pastor-Villarrubia, Mahmoud H. Elshorbagy, Jesus del Hoyo Muñoz, Francisco Jose Torcal-Milla, and Javier Alda "Diffractio: an open-source library for diffraction and interference calculations", Proc. SPIE 12997, Optics and Photonics for Advanced Dimensional Metrology III, 129971B (18 June 2024); https://doi.org/10.1117/12.3021879 79 | 80 | 81 | 82 | 0.2.3 (2023-11-21) 83 | -------------------------------- 84 | Beta state 85 | 86 | * Improvement: 87 | 88 | - XYZ drawings is removed temporally. 89 | 90 | - utils_slicer.py is deprecated. 91 | 92 | 93 | * Fix bugs: 94 | 95 | - Bug in XYZ video 96 | 97 | - Blazed grating wrong defined. 98 | 99 | - bug in Scalar_field_XY.kernelRSinverse 100 | 101 | 102 | * New features: 103 | 104 | - XY masks: new polygon, regular_polygon, star, and superformula functions. 105 | 106 | - XY masks: new circular_sector function. 107 | 108 | - XY masks: new lens_cyliindrical function. 109 | 110 | - X, XY, XYZ fields: new conjugate function. 111 | 112 | - WPM function without storing all the data. 113 | 114 | - X fields: inverse_amplitude, inverse_phase, pupil 115 | 116 | 117 | 0.1.1 (2022-10-16) 118 | -------------------------------- 119 | Beta state 120 | 121 | * Vector fields are not longer paraxial. 122 | 123 | - The propagation algorithms implemented (VRS, VFFT and VCZT) provide :E_z: field. This allows to analyze longitudinal fields.The modules and classes elliminate changes their name. For example vector_paraxial_fields_X is now vector_fields_X. 124 | 125 | 126 | * New propagation algorithm Chirped Z-Transform (CZT) is avaliable for X and XY fields. 127 | 128 | - This algorithms produce similar results to RS and VRS fields, but there are significant advantages: 129 | 130 | - The output field is not necessarily the same as the input field. This is important, for example, when analyzing the focus of a lens, since the computing time is dedicated to areas with light. 131 | 132 | - The output field does not necessarily have the same dimensionality of the input field. For example, when the mask is XY, we can have the data only at (x=0, y=0, z) axis. 133 | 134 | - Acceleration in computing and reduction of memory usage. 135 | 136 | 137 | * New modules for visualization and data analysis are provided. 138 | 139 | - Scalar_field_Z can be used, for example, to analysis of intensity light at axis. 140 | 141 | - Vector_fields_Z, Vector_fields_XZ, and Vector_fields_XYZ have been developed, as VCZT algorithm can provide these data. 142 | 143 | * Plane Wave Descomposition algorithm (PWD) is deprecated. 144 | 145 | * Some importante bugs have been solved. For example the definition of the spherical coordinates in some sources (which not used standard physics criterion). 146 | 147 | * Mask parameters is removed in some XY masks, as lenses, FPZ, etc. The new way to do this is the .pupil() function. 148 | 149 | * Smooth_refractive index can be used also for Wave Propagation Method algorithm (WPM). 150 | 151 | 152 | 153 | 0.1.0 (2022-10-12) 154 | -------------------------------- 155 | Beta state 156 | 157 | 158 | * Fix bugs: 159 | 160 | - radial and azimuthal vector waves 161 | - Change in criterion of plane waves to Physics (ISO 80000-2:2019 convention): https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions 162 | - constant_wave -> constant_polarization in vector_sources_XY 163 | - mask_circle -> pupil 164 | - 165 | 166 | * New vector_fields_XY: 167 | 168 | - vector_paraxial_fields -> vector_fields 169 | 170 | * New schemes mainly for representation: 171 | 172 | - Scalar_field_Z 173 | - vector_X, vector_Z, vector_XZ, vector_XYZ 174 | 175 | 176 | * New Scalar_mask_XY: 177 | 178 | - angular_aperture 179 | - edge_series 180 | - slit_series 181 | - rings 182 | 183 | 184 | * New propagation algorithms: 185 | 186 | - WPM and BPM in 3D 187 | - WPM and BPM in 3D without storing intermediate planes 188 | - VFFT (vector FFT and inverse FFT) 189 | - VRS (vector Rayleigh-Sommerfeld propagation, with Ez field) 190 | - Chirped z-transform (CZT) for scalar fields 191 | - Chirped z-transform (VCZT) for vector fields 192 | 193 | 194 | * Other: 195 | 196 | - Pupil function in XY and vector XY 197 | - Remove mask parameter from lenses. This may produce incompatibilities with former code 198 | - Improving drawings 199 | 200 | 201 | 0.0.13 (2021-08-11) 202 | -------------------------------- 203 | Alpha state 204 | 205 | * wpm bpm 3d, wpm without storing, xy search focus 206 | * fix bug 2D gratings 207 | * fix bug aspheric X and new aspheric XY 208 | 209 | 210 | 0.0.11 and 0.0.12 (2021-05-09) 211 | -------------------------------- 212 | Alpha state 213 | 214 | * Solved big errata in vector_paraxial_masks 215 | * Solved errata in XY: kernelRS and kernelRSinverse 216 | * Improved documentation, tutorial and examples of vector_paraxial 217 | * Scalar_mask_XY: dots 218 | * Scalar_mask_X: dots 219 | * change save_data in all classes to simplify 220 | * Changes in docs to include WPM 221 | * Execution tests 222 | 223 | 224 | 225 | 0.0.9 and 0.0.10 (2020-05-02) 226 | -------------------------------- 227 | Alpha state 228 | 229 | * Improvement to documentation (readthedocs) 230 | 231 | 232 | 233 | 0.0.7 and 0.0.8 (2020-05-02) 234 | -------------------------------- 235 | Alpha state 236 | 237 | * convert_mask -> extrude_mask 238 | * Improved documentation 239 | * Implemented PWD 240 | * Reduced size of html 241 | 242 | 243 | 244 | 0.0.6 (2019-10-22) 245 | ------------------------ 246 | Alpha state 247 | 248 | * Finished first version of examples and tutorial. 249 | 250 | 251 | 0.0.5 (2019-10-06) 252 | ------------------------ 253 | Alpha state 254 | 255 | * Included vector (fields, sources, masks) modules, tests, and tutorial. 256 | 257 | 0.0.2 (2019-10-01) 258 | ------------------------ 259 | Alpha state 260 | 261 | * copyreg removed (previous not worked) 262 | * change fft to scipy: "from scipy.fftpack import fft, ifft, fftshift" 263 | 264 | 265 | First release on PyPI in pre-alpha state. 266 | 267 | 268 | 269 | 0.0.1 (2019-02-09) 270 | ------------------------ 271 | Pre-alpha state. 272 | 273 | * Modules are passed to python3. 274 | 275 | 0.0.0 (2017-01-01) 276 | ------------------------ 277 | Pre-alpha state. 278 | 279 | * I have been developing and using the module diffractio for at least 5 years for teaching and research. It was in python2 version and not completely clear. 280 | 281 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Diffractio: Python library for Diffraction and Interference Optics. 2 | 3 | GPLv3 License 4 | 5 | Copyright (c) 2019, Luis Miguel Sanchez Brea 6 | 7 | 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see , in particular 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | recursive-include tests * 8 | recursive-exclude * __pycache__ 9 | recursive-exclude * *.py[co] 10 | 11 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif *.pdf *.mp4 *.avi 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean clean-test clean-pyc clean-build docs help 2 | .DEFAULT_GOAL := help 3 | 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | 7 | try: 8 | from urllib import pathname2url 9 | except: 10 | from urllib.request import pathname2url 11 | 12 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 13 | endef 14 | export BROWSER_PYSCRIPT 15 | 16 | define PRINT_HELP_PYSCRIPT 17 | import re, sys 18 | 19 | for line in sys.stdin: 20 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 21 | if match: 22 | target, help = match.groups() 23 | print("%-20s %s" % (target, help)) 24 | endef 25 | export PRINT_HELP_PYSCRIPT 26 | 27 | BROWSER := python3 -c "$$BROWSER_PYSCRIPT" 28 | 29 | help: 30 | @python3 -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 31 | 32 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 33 | 34 | clean-build: ## remove build artifacts 35 | rm -fr build/ 36 | rm -fr dist/ 37 | rm -fr .eggs/ 38 | find . -name '*.egg-info' -exec rm -fr {} + 39 | find . -name '*.egg' -exec rm -f {} + 40 | 41 | clean-pyc: ## remove Python file artifacts 42 | find . -name '*.pyc' -exec rm -f {} + 43 | find . -name '*.pyo' -exec rm -f {} + 44 | find . -name '*~' -exec rm -f {} + 45 | find . -name '__pycache__' -exec rm -fr {} + 46 | 47 | clean-test: ## remove test and coverage artifacts 48 | rm -fr .tox/ 49 | rm -f .coverage 50 | rm -fr htmlcov/ 51 | rm -fr .pytest_cache 52 | 53 | lint: ## check style with flake8 54 | flake8 diffractio tests 55 | 56 | test: ## run tests quickly with the default Python 57 | py.test 58 | 59 | test-all: ## run tests on every Python version with tox 60 | tox 61 | 62 | coverage: ## check code coverage quickly with the default Python 63 | coverage run --source diffractio -m pytest 64 | coverage report -m 65 | coverage html 66 | $(BROWSER) htmlcov/index.html 67 | 68 | docs: ## generate Sphinx HTML documentation, including API docs 69 | rm -f docs/diffractio.rst 70 | rm -f docs/modules.rst 71 | sphinx-apidoc -o docs/ diffractio 72 | $(MAKE) -C docs clean 73 | $(MAKE) -C docs html 74 | $(BROWSER) docs/_build/html/index.html 75 | 76 | servedocs: docs ## compile the docs watching for changes 77 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 78 | 79 | release: dist ## package and upload a release 80 | python3 -m twine upload dist/* 81 | 82 | dist: clean ## builds source and wheel package 83 | python3 setup.py sdist 84 | python3 setup.py bdist_wheel 85 | ls -l dist 86 | 87 | install: clean ## install the package to the active Python's site-packages 88 | python3 setup.py install 89 | 90 | 91 | install-develop: ## install the package in development mode. 92 | pip3 install --user -e . 93 | 94 | docs-append: ## does not remove previous Sphinx HTML, including API docs 95 | sphinx-apidoc -o docs/ diffractio 96 | $(MAKE) -C docs html 97 | $(BROWSER) docs/_build/html/index.html 98 | 99 | -------------------------------------------------------------------------------- /NEW.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | New Features 3 | ================================================ 4 | 5 | 6 | 0.3.1 (2024-10-**) 7 | -------------------------------- 8 | 9 | * Improvements: 10 | 11 | - New Algorithms for Vector propagation, in particular FPWPM. 12 | 13 | - New 3D visualization tools, using pyvista. 14 | 15 | - Use of Ezdxf for 3X DXF parts. 16 | 17 | - Improvement in documentation and examples. 18 | 19 | - Typing variables in functions. 20 | 21 | 22 | 23 | 24 | * Fix bugs: 25 | 26 | - ndgrid function -> meshgrid (for >2D matrices). 27 | 28 | 29 | * Other: 30 | 31 | - Change license to GPLv3. 32 | 33 | 34 | 0.2.3 (2023-11-21) 35 | -------------------------------- 36 | 37 | * Improvement: 38 | 39 | - XYZ drawings is removed temporally. 40 | 41 | - utils_slicer.py is deprecated. 42 | 43 | 44 | 45 | * Fix bugs: 46 | 47 | - Bug in XYZ video 48 | 49 | - Blazed grating wrong defined. 50 | 51 | - bug in Scalar_field_XY.kernelRSinverse 52 | 53 | * New features: 54 | 55 | - XY masks: new polygon, regular_polygon, star, and superformula functions. 56 | 57 | - XY masks: new circular_sector function. 58 | 59 | - XY masks: new lens_cyliindrical function. 60 | 61 | - X, XY, XYZ fields: new conjugate function. 62 | 63 | - WPM function without storing all the data. 64 | 65 | - X fields: inverse_amplitude, inverse_phase, pupil 66 | 67 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | requests = "*" 10 | 11 | [requires] 12 | python_version = "3.6" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "9838c8bf3aa442453b393e09e534ba7e1666aab4da1b9b408ecdf3ae58ab273c" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.6" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "certifi": { 20 | "hashes": [ 21 | "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", 22 | "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" 23 | ], 24 | "version": "==2018.11.29" 25 | }, 26 | "chardet": { 27 | "hashes": [ 28 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 29 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 30 | ], 31 | "version": "==3.0.4" 32 | }, 33 | "idna": { 34 | "hashes": [ 35 | "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", 36 | "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" 37 | ], 38 | "version": "==2.8" 39 | }, 40 | "requests": { 41 | "hashes": [ 42 | "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", 43 | "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" 44 | ], 45 | "index": "pypi", 46 | "version": "==2.21.0" 47 | }, 48 | "urllib3": { 49 | "hashes": [ 50 | "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", 51 | "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" 52 | ], 53 | "version": "==1.24.1" 54 | } 55 | }, 56 | "develop": {} 57 | } 58 | -------------------------------------------------------------------------------- /REFERENCES.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | References 3 | ================================================ 4 | 5 | 6 | Scalar algorithms 7 | --------------------------- 8 | 9 | **RS** 10 | 11 | * Shen, F. & Wang, A. "Fast-Fourier-transform based numerical integration method for the Rayleigh-Sommerfeld diffraction formula," Appl. Opt. 45, 1102–1110 (2006). 12 | 13 | **PWD** 14 | 15 | * Kozacki, T. "Numerical errors of diffraction computing using plane wave spectrum decomposition," Opt. Comm. 281 4219-4233 (2008). 16 | 17 | **CZT** 18 | 19 | * Bluestein, L., "A linear filtering approach to the computation of the discrete Fourier transform," Northeast Electronics Research and Engineering Meeting Record 10, 218-219 (1968). 20 | 21 | * Hu Y. et al. "Efficient full-path optical calculation of scalar and vector diffraction using the Bluestein method" Light: Science & Applications 9(119) (2020) 22 | 23 | **WPM** 24 | 25 | * Brenner K.H., Singer W. , “Light propagation through micro lenses: a new simulation method”, Appl. Opt., 32(6) 4984-4988 (1993). 26 | 27 | * Schmidt S. et al. "Wave-optical modeling beyond the thin-element-approximation" Opt. Express 24, 30188 (2016). 28 | 29 | * Brenner K.H. "A high-speed version of the wave propagation method applied to micro-optics." 16th Workshop on Information Optics (WIO). IEEE (2017) 30 | 31 | * Schmidt S. et al. "Rotationally symmetric formulation of the wave propagation method-application to the straylight analysis of diffractive lenses" Opt. Lett. 42, 1612 (2017). 32 | 33 | 34 | Scalar algorithms 35 | --------------------------- 36 | 37 | **VFFT** 38 | 39 | Kornél J. and Bokor N., 2010. “Intensity Control of the Focal Spot by Vectorial Beam Shaping.” Optics Communications 283 (24): 4859–65. https://doi.org/10.1016/j.optcom.2010.07.030. 40 | 41 | **VRS** 42 | 43 | * Ye, H. et al. "Creation of a longitudinally polarized subwavelength hotspot with an ultra-thin planar lens: Vectorial Rayleigh-Sommerfeld method" Laser Phys. Lett. 10, (2013). 44 | 45 | **VCZT** 46 | 47 | * Leutenegger M. et al. "Fast focus field calculations" Optics Express 14(23) 11277 (2006). 48 | 49 | * Hu Y. et al. "Efficient full-path optical calculation of scalar and vector diffraction using the Bluestein method" Light: Science & Applications 9(119) (2020) 50 | 51 | **FPWPM** 52 | 53 | * Wende M. et al. "Fast algorithm for the simulation of 3D-printed microoptics based on the vector wave propagation method". Opt Express. 30(22) 40161-40173 (2022) 54 | 55 | * Wende M. et al. "Fast vector wave optical simulation methods for application on 3D-printed microoptics," Journal of Optical Microsystems 4(2), 024501 (2024). 56 | 57 | sources 58 | -------------------------- 59 | 60 | * beam_width_1d (X): https://en.wikipedia.org/wiki/Beam_diameter 61 | 62 | * beam_width_4s (XY): https://en.wikipedia.org/wiki/Beam_diameter 63 | http://www.auniontech.com/ueditor/file/20170921/1505982360689799.pdf 64 | 65 | * vector fields (XY): Qwien Zhan 'Vectorial Optical Fields' 66 | 67 | Masks 68 | --------------------------- 69 | * Aspheric (X): https://www.edmundoptics.com/knowledge-center/application-notes/optics/all-about-aspheric-lenses/ 70 | 71 | * Superellipse (XY): https://en.wikipedia.org/wiki/Superellipse 72 | 73 | * Superformula (XY): Gielis, J. "A Generic Geometric Transformation that Unifies a Wide Range of Natural and Abstract Shapes." Amer. J. Botany 90, 333-338, 2003. 74 | 75 | * Roughness_1D (X), Roughness_2D (XY): JA Oglivy "Theory of wave scattering from random surfaces" Adam Hilger p.224. 76 | 77 | 78 | Util_optics 79 | -------------------------- 80 | 81 | * MTF: https://www.edmundoptics.com/resources/application-notes/optics/introduction-to-modulation-transfer-function/strehl_ratio 82 | 83 | Other References 84 | --------------------------- 85 | 86 | * J.W. Goodman, "Introduction to Fourier Optics" McGraw-Hill, 1996. 87 | 88 | * B.E. Saleh y M. C. Teich, "Fundamentals of photonics" John Wiley & Sons, 2019. 89 | 90 | * Z.Qiwen, "Vectorial optical fields: Fundamentals and applications" World scientific, 2013. 91 | 92 | * "Numerical Methods in Photonics Lecture Notes". http://ecee.colorado.edu/~mcleod/teaching/nmip/lecturenotes.html. 93 | -------------------------------------------------------------------------------- /RESULTS.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | Results obtained with Diffractio 3 | ================================================ 4 | 5 | 6 | Scientific articles 7 | ---------------------- 8 | * F.J. Torcal-Milla, L.M. Sanchez-Brea, J.A. Gomez-Pedrero "Sector-based Fresnel zone plate with extended depth of focus" Optics & Laser Technology, Vol 154, (2022) 108294 https://doi.org/10.1016/j.optlastec.2022.108294. 9 | 10 | * F.J. Torcal-Milla, L.M. Sanchez-Brea "Near field diffraction of steel tape gratings illuminated with finite-size incoherent sources" Optik, Vol 251, 2022, 168326, https://doi.org/10.1016/j.ijleo.2021.168326. 11 | 12 | * Tang, Cheng, and Jianping Li. "Quasi-non-diffracting static light sheets generated by holistically optimized pupil masks." Optics Letters 47.7 1737-1740 (2022). 13 | 14 | * Vishniakou, Ivan, and Johannes D. Seelig. "Differentiable model-based adaptive optics for two-photon microscopy." Optics Express 29.14 21418-21427 (2021). 15 | 16 | * Khasanov, I. S. & Zykova, L. A. “Terahertz ghost imaging and surface plasmon resonance microscopy : quality,” Proc. SPIE 11582, Fourth International Conference on Terahertz and Microwave Radiation: Generation, Detection, and Applications, 1158215, (2020). 17 | 18 | * Vishniakou, I. & Seelig, J. D. Differentiable model-based adaptive optics with transmitted and reflected light. Opt. Express 28, 26436 (2020). https://www.osapublishing.org/oe/abstract.cfm?uri=oe-28-18-26436 19 | 20 | * Vishniakou, I. & Seelig, J. D. Wavefront correction for adaptive optics with reflected light and deep neural networks. Opt. Express 28, 15459–15471 (2020). https://www.osapublishing.org/oe/abstract.cfm?uri=oe-28-10-15459 21 | 22 | * Sanchez-Brea, L. M., Torcal-Milla, F. J., del Hoyo, J., Cuadrado, A. & Gomez-Pedrero, J. A. Optimization of angular diffractive lenses with extended depth of focus. J. Opt. 22, 065601 (2020). https://iopscience.iop.org/article/10.1088/2040-8986/ab8614 23 | 24 | * Sanchez-Brea, L. M., Torcal-Milla, F. J. & Buencuerpo, J. Far-field diffraction of linear chirped gratings. Opt. Laser Technol. 107, 337–343 (2018). https://doi.org/10.1016/j.optlastec.2018.06.007 25 | 26 | * Torcal-Milla, F. J. & Sanchez-Brea, L. M. Single-focus binary Fresnel zone plate. Opt. Laser Technol. 97, 316–320 (2017). http://dx.doi.org/10.1016/j.optlastec.2017.07.008 27 | 28 | 29 | 30 | Congresses 31 | ---------------------- 32 | 33 | * F.J. Torcal-Milla, L.M. Sanchez-Brea, J.A. Gomez-Pedrero, A. Cuadrado "Placa zonal del Fresnel binaria sectorial" XI Reunión española de optoelectŕonica (2019). 34 | 35 | * L.M. Sanchez-Brea, J.A. Gómez Pedrero, F.J. Torcal-Milla, A. Cuadrado "Análisis difractivo del modelo de ojo"XII Reunión Nacional de Óptica (2018). 36 | -------------------------------------------------------------------------------- /STATISTICS.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | Statistics 3 | ================================================ 4 | 5 | 6 | .. toctree:: 7 | :maxdepth: 4 8 | :numbered: 9 | :glob: 10 | 11 | files_python 12 | files_jupyter 13 | functions 14 | 15 | -------------------------------------------------------------------------------- /TODO.rst: -------------------------------------------------------------------------------- 1 | ================================================ 2 | Things to do, wishes 3 | ================================================ 4 | 5 | Bugs 6 | ---------------------- 7 | - bugs in bitbucket 8 | - CZT: check a small disalignment of center from axis. 9 | - draw(kind='fft') x -> bad angles 10 | - bug granada f_zernikes 11 | 12 | In process 13 | ---------------------- 14 | - Reordering drawing functions 15 | - new parameters in get for vector_XZ and vector_XYZ, as well as XY 16 | - Vector_masks for XYZ (extrude_XY, extrude_XZ, mask_from_funcitons, etc.) 17 | - Fill masks_xz_procedures.ipynb 18 | 19 | Documentation 20 | ---------------------- 21 | - Tutorial and examples vector_XZ and vector_XYZ 22 | 23 | Algorithms 24 | ---------------------- 25 | - Pass um = 1. to um = 1e-6 at __init__: (seems to work, but have to fix drawings) 26 | - Interactive drawings for XYZ and vector_XYZ (similar to those of XY and XZ). 27 | - Implement Backpropagation for FP_WPM XZ, vector XZ and vector_XYZ. 28 | 29 | Masks and sources 30 | ---------------------- 31 | x Lenses for XZ and XYZ, including aberrations 32 | - Edges for XY and vector XY from XYZ 33 | 34 | 35 | Other 36 | ---------------------- 37 | 38 | -------------------------------------------------------------------------------- /axicon_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/axicon_result.png -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | # This is a sample build configuration for Python. 2 | # Check our guides at https://confluence.atlassian.com/x/x4UWN for more examples. 3 | # Only use spaces to indent your .yml configuration. 4 | # ----- 5 | # You can specify a custom docker image from Docker Hub as your build environment. 6 | image: python:3.6.9 7 | pipelines: 8 | default: 9 | - step: 10 | script: 11 | - pip install -r requirements.txt 12 | -------------------------------------------------------------------------------- /creating_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/creating_video.mp4 -------------------------------------------------------------------------------- /deactivate: -------------------------------------------------------------------------------- 1 | deactivate 2 | rm -rf .env 3 | python -m venv .env 4 | source ./.env/bin/activate 5 | pip install -r requirements.txt 6 | pip install -r requirements_dev.txt -------------------------------------------------------------------------------- /diffractio/__init__.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: diffractio_init.py 5 | # Purpose: Initialization for diffractio package 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | """Top-level package for Python Scalar and vector diffraction and interference. 15 | 16 | Diffractio: A scientific computing package for Scalar and Vector Optical Interference and Diffraction in Python. 17 | ================================================================================================================== 18 | 19 | 20 | """ 21 | 22 | import datetime 23 | import multiprocessing 24 | from matplotlib import cm, rcParams 25 | import matplotlib.pyplot as plt 26 | import numpy as np 27 | import scipy as sp 28 | 29 | __author__ = """Luis Miguel Sanchez Brea""" 30 | __email__ = 'optbrea@ucm.es' 31 | __version__ = '0.3.1' 32 | name = 'diffractio' 33 | 34 | um = 1. 35 | mm = 1000.*um 36 | nm = um / 1000. 37 | degrees = np.pi / 180. 38 | s = 1. 39 | seconds = 1. 40 | 41 | eps = 1e-6 42 | num_decimals = 4 43 | 44 | no_date = False # for test 45 | 46 | now = datetime.datetime.now() 47 | date_test = now.strftime("%Y-%m-%d_%H") 48 | 49 | num_max_processors = multiprocessing.cpu_count() 50 | 51 | rcParams['figure.dpi'] = 75 -------------------------------------------------------------------------------- /diffractio/config.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: config.py 5 | # Purpose: Configuration settings for diffractio package 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | """ 15 | Configuration file. Standard diffractio units are um: um = 1. 16 | """ 17 | 18 | from typing import Literal 19 | from matplotlib import cm 20 | import numpy as np 21 | 22 | bool_raise_exception = True 23 | 24 | # Configuration params for drawings 25 | CONF_DRAWING = dict() 26 | CONF_DRAWING['color_intensity'] = cm.gist_heat # cm.gist_heat #cm.hot 27 | CONF_DRAWING['color_amplitude'] = cm.jet 28 | CONF_DRAWING['color_amplitude_sign'] = cm.seismic 29 | CONF_DRAWING['color_phase'] = cm.twilight # twilight .twilight hsv 30 | CONF_DRAWING['color_real'] = cm.seismic 31 | CONF_DRAWING['color_stokes'] = cm.seismic 32 | CONF_DRAWING['color_n'] = cm.Blues 33 | # percentage of intensity not shown in phase 34 | CONF_DRAWING['percentage_intensity'] = 0.0 35 | # percentage of intensity to show Ez 36 | CONF_DRAWING['percentage_Ez'] = 0.0 37 | 38 | 39 | number_types = (int, float, complex, np.int32, np.float64) 40 | empty_types = ([], '', None) 41 | 42 | # Kind parameters for drawing 43 | Draw_refractive_index_Options = Literal['all', 'real', 'imag'] 44 | Draw_X_Options = Literal[ 'amplitude', 'intensity', 'field', 'phase', 'fill', 'fft'] 45 | Draw_Z_Options = Literal['amplitude', 'intensity', 'field', 'phase'] 46 | Draw_XZ_Options = Literal['amplitude', 'intensity', 'phase', 'real'] 47 | Draw_XY_Options = Literal['amplitude', 'intensity', 'phase', 'field', 'real_field', 'contour'] 48 | Draw_XYZ_Options = Literal['intensity', 'refractive_index'] 49 | Draw_Vector_X_Options = Literal[ 'intensity', 'intensities', 'intensities_rz', 'phases', 'fields', 'stokes'] 50 | Draw_Vector_XY_Options = Literal['intensity', 'intensities', 'intensities_rz', 'phases', 'fields', 'stokes', ' param_ellipse', 'ellipses'] 51 | Draw_Vector_XZ_Options = Literal[ 'intensity', 'intensities', 'intensities_rz', 'phases', 'fields', 'stokes'] 52 | Draw_pyvista_Options = Literal['volume', 'clip', 'slices', 'projections'] 53 | Draw_interactive_Options = Literal['intensity', 'amplitude', 'phase'] 54 | Save_mask_Options = Literal['amplitude', 'phase', 'intensity'] 55 | 56 | Options_Diffractio_kind = Literal['scalar', 'vector'] 57 | Options_Diffractio_frame = Literal['field', 'mask', 'source'] 58 | 59 | Options_add = Literal['source', 'mask', 'refractive_index', 'phases', 'no_overlap', 'distances'] 60 | Options_sub = Literal['source', 'mask', 'phases', 'no_overlap', 'refractive_index'] 61 | 62 | Options_squares_nxm = Literal['amplitude', 'intensity', 'gray_levels'] 63 | video_isovalue_Options = Literal['intensity', 'refractive_index'] 64 | 65 | get_scalar_options = Literal['intensity', 'phase','field'] 66 | get_vector_options = Literal['E', 'H', 'EH', 'fields', 'intensity', 'intensities', 'phases', 'poynting_vector', 67 | 'poynting_vector_averaged', 'poynting_total', 68 | 'energy_density', 'irradiance', 'stokes', 'params_ellipse'] 69 | 70 | -------------------------------------------------------------------------------- /diffractio/deprecated/_deprecated drawings XYZ.py: -------------------------------------------------------------------------------- 1 | def draw_XYZ_deprecated(self, 2 | kind='intensity', 3 | logarithm=False, 4 | normalize='', 5 | pixel_size=(128, 128, 128)): 6 | """Draws XZ field. 7 | 8 | Args: 9 | kind (str): type of drawing: 'intensity', 'phase', 'real_field' 10 | logarithm (float): If >0, intensity is scaled in logarithm 11 | normalize (bool): If True, max(intensity)=1 12 | pixel_size (float, float, float): pixels for drawing 13 | """ 14 | try: 15 | from ._utils_slicer import slicerLM 16 | is_slicer = True 17 | except ImportError: 18 | print("slicerLM is not loaded.") 19 | is_slicer = False 20 | 21 | if is_slicer: 22 | u_xyz_r = self.cut_resample(num_points=(128, 128, 128), 23 | new_field=True) 24 | 25 | if kind == 'intensity' or kind == '': 26 | drawing = np.abs(u_xyz_r.u)**2 27 | if kind == 'phase': 28 | drawing = np.angle(u_xyz_r.u) 29 | if kind == 'real_field': 30 | drawing = np.real(u_xyz_r.u) 31 | 32 | if logarithm == 1: 33 | drawing = np.log(drawing**0.5 + 1) 34 | 35 | if normalize == 'maximum': 36 | factor = max(0, drawing.max()) 37 | drawing = drawing / factor 38 | 39 | slicerLM(drawing) 40 | else: 41 | return 42 | 43 | 44 | def draw_volume_deprecated(self, logarithm=0, normalize='', maxintensity=None): 45 | """Draws XYZ field with mlab 46 | 47 | Args: 48 | logarithm (float): If >0, intensity is scaled in logarithm 49 | normalize (bool): If True, max(intensity)=1 50 | maxintensity (float): maximum value of intensity 51 | 52 | TODO: Simplify, drawing 53 | include kind and other parameters of draw 54 | """ 55 | 56 | try: 57 | from mayavi import mlab 58 | is_mayavi = True 59 | except ImportError: 60 | print("mayavi.mlab is not imported.") 61 | is_mayavi = False 62 | 63 | if is_mayavi: 64 | 65 | intensity = np.abs(self.u)**2 66 | 67 | if logarithm == 1: 68 | intensity = np.log(intensity + 1) 69 | 70 | if normalize == 'maximum': 71 | intensity = intensity / intensity.max() 72 | if normalize == 'area': 73 | area = (self.y[-1] - self.y[0]) * (self.z[-1] - self.z[0]) 74 | intensity = intensity / area 75 | if normalize == 'intensity': 76 | intensity = intensity / (intensity.sum() / len(intensity)) 77 | 78 | if maxintensity is None: 79 | intMin = intensity.min() 80 | intMax = intensity.max() 81 | else: 82 | intMin = maxintensity[0] 83 | intMax = maxintensity[1] 84 | 85 | mlab.figure(fgcolor=(0, 0, 0), bgcolor=(1, 1, 1)) 86 | mlab.clf() 87 | source = mlab.pipeline.scalar_field(intensity) 88 | mlab.pipeline.volume(source, 89 | vmin=intMin + 0.1 * (intMax - intMin), 90 | vmax=intMin + 0.9 * (intMax - intMin)) 91 | # mlab.view(azimuth=185, elevation=0, distance='auto') 92 | print("Close the window to continue.") 93 | mlab.show() 94 | else: 95 | return 96 | 97 | def draw_refractive_index_deprecated(self, kind='real'): 98 | """Draws XYZ refraction index with slicer 99 | 100 | Args: 101 | kind (str): 'real', 'imag', 'abs' 102 | """ 103 | try: 104 | from ._utils_slicer import slicerLM 105 | is_slicer = True 106 | except ImportError: 107 | print("slicerLM is not loaded.") 108 | is_slicer = False 109 | 110 | try: 111 | from mayavi import mlab 112 | is_mayavi = True 113 | except ImportError: 114 | print("mayavi.mlab is not imported.") 115 | is_mayavi = False 116 | 117 | if is_slicer: 118 | 119 | print("close the window to continue") 120 | if kind == 'real': 121 | slicerLM(np.real(self.n)) 122 | elif kind == 'imag': 123 | slicerLM(np.imag(self.n)) 124 | elif kind == 'abs': 125 | slicerLM(np.abs(self.n)) 126 | else: 127 | return -------------------------------------------------------------------------------- /diffractio/deprecated/_deprecated.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | """ Deprecated functions """ 4 | 5 | # utils_math 6 | 7 | import numpy as np 8 | 9 | 10 | def ndgrid_deprecated(*args, **kwargs): 11 | """n-dimensional gridding like Matlab's NDGRID. 12 | 13 | Args: 14 | The input *args are an arbitrary number of numerical sequences, e.g. lists, arrays, or tuples. 15 | The i-th dimension of the i-th output argument 16 | has copies of the i-th input argument. 17 | 18 | Example: 19 | 20 | >>> x, y, z = [0, 1], [2, 3, 4], [5, 6, 7, 8] 21 | 22 | >>> X, Y, Z = ndgrid(x, y, z) 23 | # unpacking the returned ndarray into X, Y, Z 24 | 25 | Each of X, Y, Z has shape [len(v) for v in x, y, z]. 26 | 27 | >>> X.shape == Y.shape == Z.shape == (2, 3, 4) 28 | True 29 | 30 | >>> X 31 | np.array([[[0, 0, 0, 0], 32 | [0, 0, 0, 0], 33 | [0, 0, 0, 0]], 34 | [[1, 1, 1, 1], 35 | [1, 1, 1, 1], 36 | [1, 1, 1, 1]]]) 37 | >>> Y 38 | np.array([[[2, 2, 2, 2], 39 | [3, 3, 3, 3], 40 | [4, 4, 4, 4]], 41 | [[2, 2, 2, 2], 42 | [3, 3, 3, 3], 43 | [4, 4, 4, 4]]]) 44 | >>> Z 45 | np.array([[[5, 6, 7, 8], 46 | [5, 6, 7, 8], 47 | [5, 6, 7, 8]], 48 | [[5, 6, 7, 8], 49 | [5, 6, 7, 8], 50 | [5, 6, 7, 8]]]) 51 | 52 | With an unpacked argument list: 53 | 54 | >>> V = [[0, 1], [2, 3, 4]] 55 | 56 | >>> ndgrid_deprecated(*V) # an np.array of two arrays with shape (2, 3) 57 | np.array([[[0, 0, 0], 58 | [1, 1, 1]], 59 | [[2, 3, 4], 60 | [2, 3, 4]]]) 61 | 62 | For input vectors of different data kinds, 63 | same_dtype=False makes ndgrid_deprecated() 64 | return a list of arrays with the respective dtype. 65 | >>> ndgrid_deprecated([0, 1], [1.0, 1.1, 1.2], same_dtype=False) 66 | [np.array([[0, 0, 0], [1, 1, 1]]), 67 | np.array([[ 1. , 1.1, 1.2], [ 1. , 1.1, 1.2]])] 68 | 69 | Default is to return a single np.array. 70 | 71 | >>> ndgrid_deprecated([0, 1], [1.0, 1.1, 1.2]) 72 | np.array([[[ 0. , 0. , 0. ], [ 1. , 1. , 1. ]], 73 | [[ 1. , 1.1, 1.2], [ 1. , 1.1, 1.2]]]) 74 | """ 75 | same_dtype = kwargs.get("same_dtype", True) 76 | V = [np.array(v) for v in args] # ensure all input vectors are arrays 77 | shape = [len(v) for v in args] # common shape of the outputs 78 | result = [] 79 | for i, v in enumerate(V): 80 | # reshape v so it can broadcast to the common shape 81 | # http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html 82 | zero = np.zeros(shape, dtype=v.dtype) 83 | thisshape = np.ones_like(shape) 84 | thisshape[i] = shape[i] 85 | result.append(zero + v.reshape(thisshape)) 86 | if same_dtype: 87 | return np.array(result) # converts to a common dtype 88 | else: 89 | return result # keeps separate dtype for each output 90 | 91 | 92 | # Utils_math 93 | def get_k_deprecated(x, flavour='-'): 94 | """provides k vector from x vector. Two flavours are provided (ordered + or disordered - ) 95 | 96 | Args: 97 | x (np.array): x np.array 98 | flavour (str): '+' or '-' 99 | 100 | Returns: 101 | kx (np.array): k vector 102 | 103 | Todo: 104 | Check 105 | """ 106 | 107 | num_x = x.size 108 | if flavour == '-': 109 | size_x = x[-1] - x[0] 110 | 111 | kx1 = np.linspace(0, num_x/2 + 1, int(num_x/2)) 112 | kx2 = np.linspace(-num_x/2, -1, int(num_x/2)) 113 | kx = (2 * np.pi / size_x) * np.concatenate((kx1, kx2)) 114 | 115 | elif flavour == '+': 116 | dx = x[1] - x[0] 117 | kx = 2 * np.pi / (num_x * dx) * (range(-int(num_x/2), int( 118 | num_x/2))) 119 | 120 | return kx 121 | 122 | 123 | # utils_optics 124 | # def normalize(u, kind='intensity'): 125 | # """Normalizes a field to have intensity or amplitude, etc. 1 126 | 127 | # Args: 128 | # u (numpy.array): optical field (comes usually form field.u) 129 | # kind (str): 'intensity, 'amplitude', 'logarithm'... other.. Normalization technique 130 | 131 | # Returns 132 | # u (numpy.array): normalized optical field 133 | # """ 134 | 135 | # if kind == 'intensity': 136 | # intensity_max = (np.abs(u)).max() 137 | # u = u / intensity_max 138 | # elif kind == 'amplitude': 139 | # amplitude_max = np.sqrt(np.abs(u)).max() 140 | # u = u / amplitude_max 141 | 142 | # return u 143 | 144 | # Util Optics 145 | # def normalize_vector_deprecated(u): 146 | # """Normalizes a vector to have intensity or amplitude, etc. 1 147 | 148 | # Args: 149 | # u (numpy.array): vector (last dimension should have size 2 or 3) 150 | 151 | # Returns 152 | # u (numpy.array): normalized optical field 153 | # """ 154 | # return u / np.linalg.norm(u) 155 | 156 | 157 | # vector_fields_Xy 158 | 159 | # def mask_circle(self, r0=(0., 0.), radius=0.): 160 | # """Mask vector field using a circular mask. 161 | 162 | # Args: 163 | # r0 (float, float): center of mask. 164 | # radius (float, float): radius of mask 165 | # """ 166 | 167 | # if isinstance(radius, (float, int, complex)): 168 | # radiusx, radiusy = (radius, radius) 169 | # else: 170 | # radiusx, radiusy = radius 171 | # radius = (radiusx, radiusy) 172 | 173 | # if radiusx * radiusy > 0: 174 | # radius_x = (self.x[-1] - self.x[0])/2 175 | # radius_y = (self.y[-1] - self.y[0])/2 176 | # radius = (radius_x, radius_y) 177 | 178 | # elif radius in (None, '', []): 179 | # return 180 | 181 | # elif isinstance(radius, (float, int, complex)): 182 | # radius = (radius, radius) 183 | 184 | # if r0 in (0, None, '', []): 185 | # r0_x = (self.x[-1] + self.x[0])/2 186 | # r0_y = (self.y[-1] + self.y[0])/2 187 | # r0 = (r0_x, r0_y) 188 | 189 | # if radiusx * radiusy > 0: 190 | # t1 = Scalar_mask_XY(x=self.x, y=self.y, wavelength=self.wavelength) 191 | # t1.circle(r0=r0, radius=radius, angle=0*degrees) 192 | # self.Ex = t1.u * self.Ex 193 | # self.Ey = t1.u * self.Ey 194 | # self.Ez = t1.u * self.Ez 195 | -------------------------------------------------------------------------------- /diffractio/deprecated/_utils_slicer.py: -------------------------------------------------------------------------------- 1 | 2 | """Example of an elaborate dialog showing a multiple views on the same data, with 3 cuts synchronized. 3 | 4 | This example shows how to have multiple views on the same data, how to 5 | embedded multiple scenes in a dialog, and the caveat in populating them 6 | with data, as well as how to add some interaction logic on an 7 | ImagePlaneWidget. 8 | 9 | The order in which things happen in this example is important, and it is 10 | easy to get it wrong. First of all, many properties of the visualization 11 | objects cannot be changed if there is not a scene created to view them. 12 | This is why we put a lot of the visualization logic in the callback of 13 | scene.activated, which is called after creation of the scene. 14 | Second, default values created via the '_xxx_default' callback are created 15 | lazyly, that is, when the attributes are accessed. As the establishement 16 | of the VTK pipeline can depend on the order in which it is built, we 17 | trigger these access by explicitely calling the attributes. 18 | In particular, properties like scene background color, or interaction 19 | properties cannot be set before the scene is activated. 20 | 21 | The same data is exposed in the different scenes by sharing the VTK 22 | dataset between different Mayavi data sources. See 23 | the :ref:`sharing_data_between_scenes` tip for more details. 24 | 25 | In this example, the interaction with the scene and the various elements 26 | on it is strongly simplified by turning off interaction, and choosing 27 | specific scene interactor styles. Indeed, non-technical users can be 28 | confused with too rich interaction. 29 | """ 30 | import sys 31 | 32 | try: 33 | from mayavi import mlab 34 | from mayavi.core.api import PipelineBase, Source 35 | from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor 36 | except ImportError: 37 | print("mayavi is not imported.") 38 | 39 | try: 40 | from traits.api import Array, HasTraits, Instance, on_trait_change 41 | from traitsui.api import Group, HGroup, Item, View 42 | is_traits = True 43 | except ImportError: 44 | print("traits is not imported.") 45 | is_traits = False 46 | HasTraits = object 47 | try: 48 | from tvtk.api import tvtk 49 | from tvtk.pyface.scene import Scene 50 | except ImportError: 51 | print("tvtk is not imported.") 52 | 53 | 54 | class VolumeSlicer(HasTraits): 55 | # The data to plot 56 | 57 | data = Array() 58 | 59 | # The 4 views displayed 60 | scene3d = Instance(MlabSceneModel, ()) 61 | scene_x = Instance(MlabSceneModel, ()) 62 | scene_y = Instance(MlabSceneModel, ()) 63 | scene_z = Instance(MlabSceneModel, ()) 64 | 65 | # The data source 66 | data_src3d = Instance(Source) 67 | 68 | # The image plane widgets of the 3D scene 69 | ipw_3d_x = Instance(PipelineBase) 70 | ipw_3d_y = Instance(PipelineBase) 71 | ipw_3d_z = Instance(PipelineBase) 72 | 73 | _axis_names = dict(x=0, y=1, z=2) 74 | 75 | def __init__(self, **traits): 76 | if is_traits is False: 77 | return 78 | super(VolumeSlicer, self).__init__(**traits) 79 | # Force the creation of the image_plane_widgets: 80 | self.ipw_3d_x 81 | self.ipw_3d_y 82 | self.ipw_3d_z 83 | 84 | def _data_src3d_default(self): 85 | return mlab.pipeline.scalar_field(self.data, 86 | figure=self.scene3d.mayavi_scene) 87 | 88 | def make_ipw_3d(self, axis_name): 89 | ipw = mlab.pipeline.image_plane_widget( 90 | self.data_src3d, 91 | figure=self.scene3d.mayavi_scene, 92 | plane_orientation='%s_axes' % axis_name) 93 | return ipw 94 | 95 | def _ipw_3d_x_default(self): 96 | return self.make_ipw_3d('x') 97 | 98 | def _ipw_3d_y_default(self): 99 | return self.make_ipw_3d('y') 100 | 101 | def _ipw_3d_z_default(self): 102 | return self.make_ipw_3d('z') 103 | 104 | @on_trait_change('scene3d.activated') 105 | def display_scene3d(self): 106 | mlab.pipeline.outline(self.data_src3d, 107 | figure=self.scene3d.mayavi_scene) 108 | self.scene3d.mlab.view(40, 50) 109 | # Interaction properties can only be changed after the scene 110 | # has been created, and thus the interactor exists 111 | for ipw in (self.ipw_3d_x, self.ipw_3d_y, self.ipw_3d_z): 112 | # Turn the interaction off 113 | ipw.ipw.interaction = 0 114 | self.scene3d.scene.background = (0, 0, 0) 115 | # Keep the view always pointing up 116 | self.scene3d.scene.interactor.interactor_style = tvtk.InteractorStyleTerrain( 117 | ) 118 | 119 | def make_side_view(self, axis_name): 120 | scene = getattr(self, 'scene_%s' % axis_name) 121 | 122 | # To avoid copying the data, we take a reference to the 123 | # raw VTK dataset, and pass it on to mlab. Mlab will create 124 | # a Mayavi source from the VTK without copying it. 125 | # We have to specify the figure so that the data gets 126 | # added on the figure we are interested in. 127 | outline = mlab.pipeline.outline( 128 | self.data_src3d.mlab_source.dataset, 129 | figure=scene.mayavi_scene, 130 | ) 131 | ipw = mlab.pipeline.image_plane_widget(outline, 132 | plane_orientation='%s_axes' % 133 | axis_name) 134 | setattr(self, 'ipw_%s' % axis_name, ipw) 135 | 136 | # Synchronize positions between the corresponding image plane 137 | # widgets on different views. 138 | ipw.ipw.sync_trait('slice_position', 139 | getattr(self, 'ipw_3d_%s' % axis_name).ipw) 140 | 141 | # Make left-clicking create a crosshair 142 | ipw.ipw.left_button_action = 0 143 | 144 | # Add a callback on the image plane widget interaction to 145 | # move the others 146 | def move_view(obj, evt): 147 | position = obj.GetCurrentCursorPosition() 148 | for other_axis, axis_number in self._axis_names.items(): 149 | if other_axis == axis_name: 150 | continue 151 | ipw3d = getattr(self, 'ipw_3d_%s' % other_axis) 152 | ipw3d.ipw.slice_position = position[axis_number] 153 | 154 | ipw.ipw.add_observer('InteractionEvent', move_view) 155 | ipw.ipw.add_observer('StartInteractionEvent', move_view) 156 | 157 | # Center the image plane widget 158 | ipw.ipw.slice_position = 0.5 * self.data.shape[ 159 | self._axis_names[axis_name]] 160 | 161 | # Position the view for the scene 162 | views = dict( 163 | x=(0, 90), 164 | y=(90, 90), 165 | z=(0, 0), 166 | ) 167 | scene.mlab.view(*views[axis_name]) 168 | # 2D interaction: only pan and zoom 169 | scene.scene.interactor.interactor_style = tvtk.InteractorStyleImage() 170 | scene.scene.background = (0, 0, 0) 171 | 172 | @on_trait_change('scene_x.activated') 173 | def display_scene_x(self): 174 | return self.make_side_view('x') 175 | 176 | @on_trait_change('scene_y.activated') 177 | def display_scene_y(self): 178 | return self.make_side_view('y') 179 | 180 | @on_trait_change('scene_z.activated') 181 | def display_scene_z(self): 182 | return self.make_side_view('z') 183 | 184 | # --------------------------------------------------------------------------- 185 | # The layout of the dialog created 186 | # --------------------------------------------------------------------------- 187 | view = View( 188 | HGroup( 189 | Group( 190 | Item('scene_y', 191 | editor=SceneEditor(scene_class=Scene), 192 | height=250, 193 | width=300), 194 | Item('scene_z', 195 | editor=SceneEditor(scene_class=Scene), 196 | height=250, 197 | width=300), 198 | show_labels=False, 199 | ), 200 | Group( 201 | Item('scene_x', 202 | editor=SceneEditor(scene_class=Scene), 203 | height=250, 204 | width=300), 205 | Item('scene3d', 206 | editor=SceneEditor(scene_class=MayaviScene), 207 | height=250, 208 | width=300), 209 | show_labels=False, 210 | ), 211 | ), 212 | resizable=True, 213 | title='Diffractio', 214 | ) 215 | 216 | 217 | def slicerLM(fxyz): 218 | modules_name = 'tvtk', 'traits', 'mayavi' 219 | is_all_charged = True 220 | for module_name in modules_name: 221 | if module_name not in sys.modules: 222 | print('Module {} has not been imported'.format(module_name)) 223 | is_all_charged = False 224 | if is_all_charged is True: 225 | m = VolumeSlicer(data=fxyz) 226 | m.configure_traits() 227 | else: 228 | print( 229 | "slicerLM cannot be used since tvtk, traits or mayavi modules are not imported" 230 | ) 231 | -------------------------------------------------------------------------------- /diffractio/diffractio.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: Diffractio.py 5 | # Purpose: Class for controlling the other modules. 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | """ 15 | This module 16 | 17 | 18 | """ 19 | # flake8: noqa 20 | 21 | 22 | # import copy 23 | # import copyreg 24 | # import multiprocessing 25 | # import time 26 | # import types 27 | 28 | 29 | 30 | # from numpy import angle, array, concatenate, exp, linspace, pi, shape, sqrt, zeros 31 | # from numpy.lib.scimath import sqrt as csqrt 32 | # from scipy.fftpack import fft, fftshift, ifft 33 | # from scipy.interpolate import interp1d 34 | # from scipy.special import hankel1 35 | 36 | # from .__init__ import degrees, mm, np, plt 37 | 38 | # from .config import bool_raise_exception, Draw_X_Options, get_scalar_options, empty_types 39 | # from .utils_typing import npt, Any, NDArray, NDArrayFloat, NDArrayComplex 40 | # from .utils_common import get_date, load_data_common, save_data_common, check_none, add, oversampling 41 | # from .utils_drawing import normalize_draw 42 | # from .utils_math import (fft_filter, get_edges, nearest, reduce_to_1, Bluestein_dft_x, get_k, nearest2) 43 | # from .utils_multiprocessing import (_pickle_method, _unpickle_method, 44 | # execute_multiprocessing) 45 | # from .utils_optics import field_parameters, normalize_field 46 | 47 | # copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method) 48 | 49 | # num_max_processors = multiprocessing.cpu_count() 50 | 51 | 52 | from .config import Options_Diffractio_kind, Options_Diffractio_frame 53 | 54 | from diffractio.scalar_fields_X import Scalar_field_X 55 | from diffractio.scalar_fields_XY import Scalar_field_XY 56 | from diffractio.scalar_fields_XYZ import Scalar_field_XYZ 57 | from diffractio.scalar_fields_XZ import Scalar_field_XZ 58 | from diffractio.scalar_fields_Z import Scalar_field_Z 59 | 60 | from diffractio.scalar_masks_X import Scalar_mask_X 61 | from diffractio.scalar_masks_XY import Scalar_mask_XY 62 | from diffractio.scalar_masks_XYZ import Scalar_mask_XYZ 63 | from diffractio.scalar_masks_XZ import Scalar_mask_XZ 64 | 65 | from diffractio.scalar_sources_X import Scalar_source_X 66 | from diffractio.scalar_sources_XY import Scalar_source_XY 67 | 68 | from diffractio.vector_fields_X import Vector_field_X 69 | from diffractio.vector_fields_XY import Vector_field_XY 70 | from diffractio.vector_fields_XYZ import Vector_field_XYZ 71 | from diffractio.vector_fields_XZ import Vector_field_XZ 72 | from diffractio.vector_fields_Z import Vector_field_Z 73 | 74 | from diffractio.vector_masks_XY import Vector_mask_XY 75 | from diffractio.vector_sources_XY import Vector_source_XY 76 | 77 | from diffractio.utils_typing import NDArrayFloat 78 | 79 | class Diffractio(): 80 | """Class for unidimensional scalar fields. 81 | 82 | Args: 83 | x (numpy.array): linear array with equidistant positions. 84 | The number of data is preferibly :math:`2^n` . 85 | wavelength (float): wavelength of the incident field 86 | n_background (float): refractive index of background 87 | info (str): String with info about the simulation 88 | 89 | Attributes: 90 | self.x (numpy.array): Linear array with equidistant positions. 91 | The number of data is preferibly :math:`2^n`. 92 | self.wavelength (float): Wavelength of the incident field. 93 | self.u (numpy.array): Complex field. The size is equal to self.x. 94 | self.quality (float): Quality of RS algorithm. 95 | self.info (str): Description of data. 96 | self.type (str): Class of the field. 97 | self.date (str): Date when performed. 98 | """ 99 | 100 | def __init__(self, 101 | kind: Options_Diffractio_kind, 102 | frame: Options_Diffractio_frame, 103 | x: NDArrayFloat | None = None, 104 | y: NDArrayFloat | None = None, 105 | z: NDArrayFloat | None = None, 106 | wavelength: float = 0, 107 | n_background: float = 1., 108 | info: str = ""): 109 | 110 | if kind == 'scalar': 111 | if x is not None and y is None and z is None: 112 | if frame == 'source': 113 | self.__class__ = Scalar_source_X 114 | self.__init__(x, wavelength, n_background, info) 115 | elif frame == 'mask': 116 | self.__class__ = Scalar_mask_X 117 | self.__init__(x, wavelength, n_background, info) 118 | elif frame == 'field': 119 | self.__class__ = Scalar_field_X 120 | self.__init__(x, wavelength, n_background, info) 121 | elif x is not None and y is not None and z is None: 122 | if frame == 'source': 123 | self.__class__ = Scalar_source_XY 124 | self.__init__(x, y, wavelength, n_background, info) 125 | elif frame == 'mask': 126 | self.__class__ = Scalar_mask_XY 127 | self.__init__(x, y, wavelength, n_background, info) 128 | elif frame == 'field': 129 | self.__class__ = Scalar_field_XY 130 | self.__init__(x, y, wavelength, n_background, info) 131 | elif x is not None and y is None and z is not None: 132 | if frame == 'mask': 133 | self.__class__ = Scalar_mask_XZ 134 | self.__init__(x, z, wavelength, n_background, info) 135 | elif frame == 'field': 136 | self.__class__ = Scalar_field_XZ 137 | self.__init__(x, z, wavelength, n_background, info) 138 | elif x is not None and y is not None and z is not None: 139 | if frame == 'mask': 140 | self.__class__ = Scalar_mask_XYZ 141 | self.__init__(x, y, z, wavelength, n_background, info) 142 | elif frame == 'field': 143 | self.__class__ = Scalar_field_XYZ 144 | self.__init__(x, y, z, wavelength, n_background, info) 145 | elif x is None and y is None and z is not None: 146 | if frame == 'field': 147 | self.__class__ = Scalar_field_Z 148 | self.__init__(z, wavelength, n_background, info) 149 | else: 150 | raise ValueError('frame must be source, mask or field') 151 | elif kind == 'vector': 152 | if x is not None and y is None and z is None: 153 | if frame == 'field': 154 | self.__class__ = Vector_field_X 155 | self.__init__(x, wavelength, n_background, info) 156 | elif x is not None and y is not None and z is None: 157 | if frame == 'field': 158 | self.__class__ = Vector_field_XY 159 | self.__init__(x, y, wavelength, n_background, info) 160 | elif frame == 'mask': 161 | self.__class__ = Vector_mask_XY 162 | self.__init__(x, y, wavelength, n_background, info) 163 | elif frame == 'source': 164 | self.__class__ = Vector_source_XY 165 | self.__init__(x, y, wavelength, n_background, info) 166 | elif x is not None and y is None and z is not None: 167 | if frame == 'field': 168 | self.__class__ = Vector_field_XZ 169 | self.__init__(x, z, wavelength, n_background, info) 170 | elif x is not None and y is not None and z is not None: 171 | if frame == 'field': 172 | self.__class__ = Vector_field_XYZ 173 | self.__init__(x, y, z, wavelength, n_background, info) 174 | elif x is None and y is None and z is not None: 175 | if frame == 'field': 176 | self.__class__ = Vector_field_Z 177 | self.__init__(z, wavelength, n_background, info) 178 | else: 179 | raise ValueError('frame must be fields, source or mask') 180 | else: 181 | raise ValueError('kind must be scalar or vector') -------------------------------------------------------------------------------- /diffractio/other/count_number_lines.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | def list_python_files_and_line_counts(directory: str, ext: str) -> tuple[tuple[str, int]]: 5 | """List Python files and their line counts in a given directory. 6 | 7 | Args: 8 | directory (str): The directory to search for Python files. 9 | 10 | Returns: 11 | tuple[tuple[str, int]]: A list of tuples containing the file name and line count. 12 | """ 13 | 14 | num_lines = 0 15 | python_files = [] 16 | 17 | for root, _, files in os.walk(directory): 18 | for file in sorted(files): 19 | if file.endswith(ext) and not file.startswith("_"): 20 | file_path = os.path.join(root, file) 21 | with open(file_path, 'r', encoding='utf-8') as f: 22 | line_count = sum(1 for _ in f) 23 | python_files.append((file, line_count)) 24 | num_lines = num_lines + line_count 25 | return python_files, num_lines 26 | 27 | 28 | directory_path = "../diffractio" 29 | python_files, num_lines = list_python_files_and_line_counts(directory_path, ".py") 30 | 31 | with open("docs/files_python.rst", 'w') as f: 32 | 33 | text = f"Python files" 34 | print(text) 35 | f.write(text+"\n") 36 | f.write("================================\n\n") 37 | 38 | for file_name, line_count in sorted(python_files): 39 | text = f" - {file_name}: {line_count} lines" 40 | print(text) 41 | f.write(text+"\n") 42 | 43 | 44 | text = f"\nTotal number of lines in Python files: {num_lines}" 45 | print(text) 46 | f.write(text+"\n") 47 | 48 | 49 | 50 | directory_path = "../diffractio/docs/source" 51 | python_files, num_lines = list_python_files_and_line_counts(directory_path, ".ipynb") 52 | 53 | 54 | 55 | with open("docs/files_jupyter.rst", 'w') as f: 56 | text = f"Jupyter files" 57 | print(text) 58 | f.write(text+"\n") 59 | f.write("================================\n\n") 60 | 61 | for file_name, line_count in sorted(python_files): 62 | text = f" - {file_name}: {line_count} lines" 63 | print(text) 64 | f.write(text+"\n") 65 | 66 | 67 | text = f"\nTotal number of lines in Python files: {num_lines}" 68 | print(text) 69 | f.write(text+"\n") 70 | -------------------------------------------------------------------------------- /diffractio/other/get_functions.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def list_python_files(directory): 4 | try: 5 | files = [f for f in os.listdir(directory) if f.endswith('.py')] 6 | return files 7 | except FileNotFoundError: 8 | return f"The directory {directory} does not exist." 9 | 10 | print(os.getcwd()) 11 | directory = '/home/luismiguel/github/diffractio/diffractio/' 12 | python_files = list_python_files(directory) 13 | 14 | 15 | def list_classes_and_functions(file_path): 16 | """ 17 | list_classes_and_functions _summary_ 18 | 19 | _extended_summary_ 20 | 21 | Args: 22 | file_path (_type_): _description_ 23 | 24 | Returns: 25 | _type_: _description_ 26 | """ 27 | 28 | classes = [] 29 | functions = [] 30 | 31 | with open(file_path, 'r') as file: 32 | file_content = file.read() 33 | 34 | # Extract classes and functions without using exec 35 | for line in file_content.splitlines(): 36 | if line.strip().startswith('class '): 37 | class_name = line.split()[1].split('(')[0] 38 | classes.append(class_name) 39 | elif line.strip().startswith('def '): 40 | function_name = line.split()[1].split('(')[0] 41 | functions.append(function_name) 42 | # Initialize class_functions after extracting class names 43 | class_functions = {class_name: [] for class_name in classes} 44 | standalone_functions = [] 45 | 46 | current_class = None 47 | for line in file_content.splitlines(): 48 | if line.strip().startswith('class '): 49 | current_class = line.split()[1].split('(')[0] 50 | elif line.strip().startswith('def '): 51 | function_name = line.split()[1].split('(')[0] 52 | if current_class: 53 | class_functions[current_class].append(function_name) 54 | else: 55 | standalone_functions.append(function_name) 56 | 57 | return classes, standalone_functions, class_functions 58 | 59 | def print_data_from_file(file_path) -> None: 60 | classes, standalone_functions, class_functions = list_classes_and_functions(file_path) 61 | print("Classes:") 62 | for cl in classes: 63 | print(cl) 64 | for function in class_functions[cl]: 65 | print(" {}".format(function)) 66 | print("Standalone functions:") 67 | for function in standalone_functions: 68 | print(function) 69 | 70 | 71 | num_functions = 0 72 | 73 | with open('docs/functions.rst', 'w') as rst_file: 74 | rst_file.write("Functions:\n") 75 | rst_file.write("================================\n\n") 76 | for file in sorted(python_files): 77 | rst_file.write(f"{file}\n") 78 | rst_file.write("__________________________________________________\n\n") 79 | 80 | file_path = os.path.join(directory, file) 81 | classes, standalone_functions, class_functions = list_classes_and_functions(file_path) 82 | for cl in classes: 83 | if cl not in ('', [], None): 84 | rst_file.write(f" Class: **{cl}**. ({len(class_functions[cl])} functions)\n") 85 | num_functions += len(class_functions[cl]) 86 | 87 | for function in sorted(class_functions[cl]): 88 | rst_file.write(f" - {function}\n\n") 89 | 90 | if len(standalone_functions) > 0: 91 | rst_file.write(f"\n Standalone functions: ({len(standalone_functions)} functions)\n\n") 92 | num_functions += len(standalone_functions) 93 | 94 | for function in sorted(standalone_functions): 95 | rst_file.write(f" - {function}\n\n") 96 | rst_file.write("\n\n\n\n") 97 | 98 | rst_file.write(f"Summary\n") 99 | rst_file.write(f"============================\n\n") 100 | 101 | ## Number of lines in each file 102 | 103 | for file in python_files: 104 | file_path = os.path.join(directory, file) 105 | classes, standalone_functions, class_functions = list_classes_and_functions(file_path) 106 | rst_file.write(f"\n**{file}**\n\n") 107 | 108 | with open(file_path, 'r') as f: 109 | lines = f.readlines() 110 | num_lines = len(lines) 111 | rst_file.write(f" Number of lines: {num_lines}\n\n") 112 | 113 | if len(classes)>0: 114 | rst_file.write(f" Number of classes: {len(classes)}\n\n") 115 | for cl in classes: 116 | if len(class_functions[cl]) > 0: 117 | rst_file.write(f" Class: {cl}, Number of functions: {len(class_functions[cl])}\n\n") 118 | 119 | 120 | total_lines = sum(len(open(os.path.join(directory, file), 'r').readlines()) for file in python_files) 121 | 122 | rst_file.write(f"Total\n") 123 | rst_file.write(f"============================\n\n") 124 | rst_file.write(f" Total number of Python files: {len(python_files)}\n\n") 125 | rst_file.write(f" Total number of functions: {num_functions}\n\n") 126 | rst_file.write(f" Total number of lines across all files: {total_lines}\n\n") 127 | -------------------------------------------------------------------------------- /diffractio/scalar_sources_X.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: scalar_sources_X.py 5 | # Purpose: Define the Scalar_source_X class for unidimensional scalar sources 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | """ 15 | This module generates Scalar_field_X class for defining sources. 16 | Its parent is Scalar_field_X. 17 | 18 | The main atributes are: 19 | * self.u - field 20 | * self.x - x positions of the field 21 | * self.wavelength - wavelength of the incident field. The field is monocromatic 22 | 23 | The magnitude is related to microns: `mifcron = 1.` 24 | 25 | *Class for unidimensional scalar masks* 26 | 27 | *Functions* 28 | * plane_wave 29 | * gauss_beam 30 | * spherical_wave 31 | * plane_waves_dict 32 | * plane_waves_several_inclined 33 | * gauss_beams_several_parallel 34 | * gauss_beams_several_inclined 35 | 36 | *Also* 37 | * Polychromatic and extendes sources are defined in scalar_fields_X.py for multiprocessing purposes. 38 | """ 39 | # flake8: noqa 40 | 41 | 42 | 43 | from .__init__ import degrees, np, um 44 | from .utils_typing import npt, Any, NDArray, NDArrayFloat, NDArrayComplex 45 | from .utils_common import check_none 46 | from .config import bool_raise_exception 47 | from .scalar_fields_X import Scalar_field_X 48 | 49 | 50 | class Scalar_source_X(Scalar_field_X): 51 | """Class for unidimensional scalar sources. 52 | 53 | Args: 54 | x (numpy.array): linear array with equidistant positions. The number of data is preferibly :math:`2^n` . 55 | wavelength (float): wavelength of the incident field 56 | n_background (float): refractive index of background 57 | info (str): String with info about the simulation 58 | 59 | Attributes: 60 | self.x (numpy.array): linear array with equidistant positions. The number of data is preferibly :math:`2^n` . 61 | self.wavelength (float): wavelength of the incident field. 62 | self.u (numpy.array): equal size than x. complex field 63 | self.quality (float): quality of RS algorithm 64 | self.info (str): description of data 65 | self.type (str): Class of the field 66 | self.date (str): date when performed 67 | """ 68 | 69 | def __init__(self, x: NDArrayFloat | None = None, wavelength: float = 0, 70 | n_background: float = 1., info: str = ""): 71 | super().__init__(x, wavelength, n_background, info) 72 | self.type = 'Scalar_source_X' 73 | 74 | @check_none('x',raise_exception=bool_raise_exception) 75 | def plane_wave(self, A: float = 1., theta: float = 0., z0: float = 0.): 76 | """Plane wave. 77 | 78 | Args: 79 | A (float): maximum amplitude 80 | theta (float): angle in radians 81 | z0 (float): constant value for phase shift 82 | """ 83 | # Definicion del vector de onda 84 | k = 2 * np.pi / self.wavelength 85 | self.u = A * np.exp(1.j * k * (self.x * np.sin(theta) + z0 * np.cos(theta))) 86 | 87 | 88 | @check_none('x',raise_exception=bool_raise_exception) 89 | def gauss_beam(self, x0: float, w0: float, z0: float, A: float = 1, theta: float = 0.): 90 | """Gauss Beam. 91 | 92 | Args: 93 | x0 (float): x position of center 94 | w0 (float): minimum beam width 95 | z0 (float): position of beam width 96 | A (float): maximum amplitude 97 | theta (float): angle in radians 98 | """ 99 | k = 2 * np.pi / self.wavelength 100 | # distance de Rayleigh solo para una direccion. 101 | z_rayleigh = k * w0**2/2 102 | 103 | phaseGouy = np.arctan2(z0, z_rayleigh) 104 | 105 | w = w0 * np.sqrt(1 + (z0 / z_rayleigh)**2) 106 | if z0 == 0: 107 | R = 1e10 108 | else: 109 | R = -z0 * (1 + (z_rayleigh / z0)**2) 110 | amplitude = A * w0 / w * np.exp(-(self.x - x0)**2 / (w**2)) 111 | phase1 = np.exp(1j * k * ((self.x - x0) * np.sin(theta))) # rotation 112 | phase2 = np.exp(1j * (-k * z0 - phaseGouy + k * (self.x - x0)**2 / 113 | (2 * R))) 114 | 115 | self.u = amplitude * phase1 * phase2 116 | 117 | 118 | @check_none('x',raise_exception=bool_raise_exception) 119 | def spherical_wave(self, A: float, x0: float, z0: float, normalize: bool = False): 120 | """Spherical wave. self.u = amplitude * A * np.exp(-1.j * np.sign(z0) * k * Rz) / Rz 121 | 122 | Args: 123 | A (float): maximum amplitude 124 | x0 (float): x position of source 125 | z0 (float): z position of source 126 | mask (bool): If true, masks the spherical wave with radius 127 | normalize (bool): If True, maximum of field is 1 128 | """ 129 | k = 2 * np.pi / self.wavelength 130 | 131 | Rz = np.sqrt((self.x - x0)**2 + z0**2) 132 | 133 | # Onda esferica 134 | self.u = A * np.exp(-1.j * np.sign(z0) * k * Rz) / Rz 135 | 136 | if normalize is True: 137 | self.u = self.u / np.abs(self.u.max() + 1.012034e-12) 138 | 139 | 140 | @check_none('x',raise_exception=bool_raise_exception) 141 | def plane_waves_dict(self, params: dict): 142 | """Several plane waves with parameters defined in dictionary 143 | 144 | Args: 145 | params: list with a dictionary: 146 | A (float): maximum amplitude 147 | theta (float): angle in radians 148 | z0 (float): constant value for phase shift 149 | """ 150 | # Definicion del vector de onda 151 | k = 2 * np.pi / self.wavelength 152 | 153 | self.u = np.zeros_like(self.x, dtype=complex) 154 | for p in params: 155 | self.u = self.u + p['A'] * np.exp( 156 | 1.j * k * 157 | (self.x * np.sin(p['theta']) + p['z0'] * np.cos(p['theta']))) 158 | 159 | 160 | @check_none('x',raise_exception=bool_raise_exception) 161 | def plane_waves_several_inclined(self, A: float, num_beams: int, max_angle: float): 162 | """Several paralel plane waves. 163 | 164 | Args: 165 | A (float): maximum amplitude 166 | num_beams (int): number of ints 167 | max_angle (float): maximum angle for beams 168 | """ 169 | 170 | t = np.zeros_like(self.x, dtype=complex) 171 | angle = max_angle / num_beams 172 | for i in range(num_beams): 173 | theta = -max_angle/2 + angle * (i + 0.5) 174 | self.plane_wave(theta=theta, z0=0) 175 | t = t + self.u 176 | self.u = t 177 | 178 | 179 | @check_none('x',raise_exception=bool_raise_exception) 180 | def gauss_beams_several_parallel(self, A: float, num_beams: int, w0: float, z0: float, x_central: float, x_range: float, theta: float = 0.): 181 | """Several parallel gauss beams 182 | 183 | Args: 184 | A (float): maximum amplitude 185 | num_beams (int): number of gaussian beams (equidistintan) 186 | w0 (float): beam width of the bemas 187 | z0 (float): constant value for phase shift 188 | x_central (float): central position of rays 189 | x_range (float): range of rays 190 | theta (float): angle of the parallel beams 191 | """ 192 | 193 | t = np.zeros_like(self.x, dtype=complex) 194 | distancia = x_range / num_beams 195 | for i in range(num_beams): 196 | xi = x_central - x_range/2 + distancia * (i + 0.5) 197 | self.gauss_beam(x0=xi, w0=w0, z0=z0, A=A, theta=theta) 198 | t = t + self.u 199 | self.u = t 200 | 201 | @check_none('x',raise_exception=bool_raise_exception) 202 | def gauss_beams_several_inclined(self, A: float, num_beams: int, w0: float, x0: float, z0: float, max_angle: float): 203 | """Several inclined gauss beams 204 | 205 | Args: 206 | A (float): maximum amplitude 207 | num_beams (int): number of gaussian beams (equidistintan) 208 | w0 (float): beam width of the bemas 209 | x0 (fl(float): maximum amplitude 210 | num_beams (int): number of ints 211 | maoat): initial position of gauss beam at x 212 | z0 (float): constant value for phase shift 213 | max_angle (float): maximum angle for beams 214 | """ 215 | 216 | t = np.zeros_like(self.x, dtype=complex) 217 | angle = max_angle / num_beams 218 | for i in range(num_beams): 219 | thetai = -max_angle/2 + angle * (i + 0.5) 220 | self.gauss_beam(x0=x0, w0=w0, z0=z0, A=A, theta=thetai) 221 | t = t + self.u 222 | self.u = t 223 | -------------------------------------------------------------------------------- /diffractio/utils_dxf.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: utils_dxf.py 5 | # Purpose: Common functions to dxf files. It mainly uses ezdxf pachage 6 | # 7 | # 8 | # Author: Luis Miguel Sanchez Brea 9 | # 10 | # Created: 2024 11 | # Copyright: (c) Luis Miguel Sanchez-Brea AOCG / UCM 12 | # License: GPLv3 License 13 | # ---------------------------------------------------------------------- 14 | # EZDXF by Manfred Moitzi 15 | 16 | 17 | from __future__ import annotations 18 | 19 | import os 20 | import sys 21 | 22 | from PIL import Image 23 | 24 | import ezdxf 25 | from ezdxf import recover 26 | from ezdxf import bbox 27 | from ezdxf.addons.drawing import RenderContext, Frontend 28 | from ezdxf.addons.drawing.matplotlib import MatplotlibBackend 29 | from ezdxf.layouts import Modelspace 30 | 31 | 32 | from .utils_typing import npt, Any, NDArray, NDArrayFloat, NDArrayComplex 33 | from .import np, plt 34 | 35 | 36 | def set_pixel_density(fig: plt.Figure, ax: plt.Axes, ppu: int): 37 | """_summary_ 38 | 39 | Args: 40 | fig (plt.Figure): _description_ 41 | ax (plt.Axes): _description_ 42 | ppu (int): pixels per drawing unit. 43 | """ 44 | 45 | xmin, xmax = ax.get_xlim() 46 | width = xmax - xmin 47 | ymin, ymax = ax.get_ylim() 48 | height = ymax - ymin 49 | dpi = fig.dpi 50 | width_inch = width * ppu / dpi 51 | height_inch = height * ppu / dpi 52 | fig.set_size_inches(width_inch, height_inch) 53 | 54 | 55 | def set_pixel_size(fig: plt.Figure, size: tuple[int, int]): 56 | """_summary_ 57 | 58 | Args: 59 | fig (plt.Figure): _description_ 60 | size (tuple[int, int]): _description_ 61 | 62 | Returns: 63 | _type_: _description_ 64 | """ 65 | x, y = size 66 | fig.set_size_inches(x / fig.dpi, y / fig.dpi) 67 | return fig 68 | 69 | 70 | def binarize(image, center_level=128): 71 | """_summary_ 72 | 73 | Args: 74 | image (_type_): _description_ 75 | center_level (int, optional): _description_. Defaults to 128. 76 | 77 | Returns: 78 | _type_: _description_ 79 | """ 80 | 81 | image_new = np.zeros_like(image) 82 | image_new[image < center_level] = 0 83 | image_new[image > center_level] = 1 84 | 85 | return image_new 86 | 87 | 88 | def load_dxf(filename_dxf: str, num_pixels: tuple[int, int], verbose: bool = False): 89 | """_summary_ 90 | 91 | Args: 92 | filename_dxf (_type_): _description_ 93 | num_pixels (_type_): _description_ 94 | filename_png (str, optional): _description_. Defaults to ''. 95 | 96 | 97 | Returns: 98 | _type_: _description_ 99 | 100 | """ 101 | # Example frame: 102 | # frame: dict or bool = False, 103 | # r0 = np.array((0*um, 0)) 104 | # extent_dxf = [-500*um, +500*um, -250*um, +250*um] 105 | 106 | # temporal, for debugging 107 | filename_png = '' 108 | has_draw = False 109 | 110 | try: 111 | doc, auditor = recover.readfile(filename_dxf) 112 | except IOError: 113 | print(f'Not a DXF file or a generic I/O error.') 114 | sys.exit(1) 115 | except ezdxf.DXFStructureError: 116 | print(f'{"Invalid or corrupted DXF file."}') 117 | sys.exit(2) 118 | 119 | if filename_png == '': 120 | filename_png2 = "temp.png" 121 | else: 122 | filename_png2 = filename_png 123 | 124 | msp = doc.modelspace() 125 | 126 | # The auditor.errors attribute stores severe errors, 127 | # which may raise exceptions when rendering. 128 | if not auditor.has_errors: 129 | fig: plt.Figure = plt.figure() 130 | ax: plt.Axes = fig.add_axes([0, 0, 1, 1]) 131 | ctx = RenderContext(doc) 132 | ctx.current_layout_properties.set_colors(bg='#000000') 133 | 134 | out = MatplotlibBackend(ax) 135 | Frontend(ctx, out).draw_layout(msp, finalize=True) 136 | 137 | # set margins as you like (as relative factor of width and height) 138 | ax.margins(0) 139 | # export image with a size of 1000x600 pixels 140 | fig = set_pixel_size(fig, num_pixels) 141 | fig.savefig(filename_png2, facecolor='#000000', edgecolor='#FFFFFF') 142 | fig.clear() 143 | 144 | cache = bbox.Cache() 145 | # get overall bounding box 146 | bounding_box = bbox.extents(msp, cache=cache) 147 | 148 | p1 = bounding_box.extmin 149 | p2 = bounding_box.extmax 150 | 151 | p_min = np.array((p1[0], p1[1])) 152 | p_max = np.array((p2[0], p2[1])) 153 | 154 | im_frame = Image.open(filename_png2) 155 | 156 | np_frame = np.array(im_frame.getdata()) 157 | 158 | im = np.asarray(np_frame[:, 0].reshape([num_pixels[1], num_pixels[0]])) 159 | 160 | image_new = binarize(im, 128) 161 | 162 | # if frame is not False: 163 | # r0 = frame['r0'] 164 | # ext_dxf = frame['extension'] 165 | # points0 = np.array([(ext_dxf[0], ext_dxf[2]), (ext_dxf[1], ext_dxf[2]), 166 | # (ext_dxf[1], ext_dxf[3]), (ext_dxf[0], ext_dxf[3])]) 167 | # points0 = points0 + r0 168 | # msp.add_lwpolyline(points0, close=True, dxfattribs={"color": 6}) 169 | 170 | if verbose: 171 | print("p_min = ", p_min) 172 | print("p_max = ", p_max) 173 | print("frame size: ", im_frame.size) 174 | # print(im_frame.format) 175 | # print(im_frame.mode) 176 | # print(image_new.min(), image_new.max()) 177 | 178 | if filename_png == '': 179 | os.remove(filename_png2) 180 | 181 | if has_draw: 182 | plt.figure() 183 | plt.imshow(image_new, cmap='gray') 184 | plt.colorbar() 185 | plt.clim(0, 1) 186 | 187 | return image_new, p_min, p_max, msp 188 | -------------------------------------------------------------------------------- /diffractio/utils_multiprocessing.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: utils_multiprocessing.py 5 | # Purpose: Utility functions for multiprocessing operations 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | # flake8: noqa 14 | 15 | import copyreg 16 | import multiprocessing 17 | import time 18 | import types 19 | from multiprocessing import Pool 20 | 21 | import numpy as np 22 | 23 | 24 | from .utils_typing import npt, Any, NDArray, NDArrayFloat, NDArrayComplex 25 | 26 | 27 | def _pickle_method(method): 28 | """function for multiprocessing in class 29 | 30 | """ 31 | func_name = method.im_func.__name__ 32 | obj = method.im_self 33 | cls = method.im_class 34 | if func_name.startswith( 35 | '__') and not func_name.endswith('__'): # deal with mangled names 36 | cls_name = cls.__name__.lstrip('_') 37 | func_name = '_' + cls_name + func_name 38 | return _unpickle_method, (func_name, obj, cls) 39 | 40 | 41 | def _unpickle_method(func_name, obj, cls): 42 | """ 43 | function for multiprocessing in class 44 | """ 45 | for cls in cls.__mro__: 46 | try: 47 | func = cls.__dict__[func_name] 48 | except KeyError: 49 | pass 50 | else: 51 | break 52 | return func.__get__(obj, cls) 53 | 54 | 55 | copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method) 56 | 57 | 58 | # Funcion inversa a la anterior 59 | def separate_from_iterable(iterable, shape=0): 60 | """This function does somehow the opposite of the previous one, it takes an iterable made of lists and separates each one in a different variable, reshaped with the desired shape 61 | """ 62 | # Averiguar el numero de variables diferentes que habra 63 | N_var = len(iterable[0]) 64 | # Make iterable array 65 | iterable = np.array(iterable) 66 | # Cambiar la forma de las variables 67 | variables = range(N_var) 68 | for indV in range(N_var): 69 | if shape == 0: 70 | variables[indV] = iterable[:, indV] 71 | else: 72 | variables[indV] = np.reshape(iterable[:, indV], shape) 73 | # Fin 74 | return variables 75 | 76 | 77 | class auxiliar_multiprocessing(): 78 | 79 | def __init__(self): 80 | pass 81 | 82 | # Method that executes the multiprocessing 83 | def execute_multiprocessing(self, 84 | function, 85 | var_iterable, 86 | dict_constants=dict(), 87 | Ncores=8): 88 | # Store data in object 89 | self.external_function = function 90 | self.dict_constants = dict_constants 91 | # Start multiprocessing if more than one core is required 92 | if Ncores > 1: 93 | pool = Pool(Ncores) 94 | print('Starting multiprocessing') 95 | result = pool.map(self.method_single_proc, var_iterable) 96 | print('Multiprocessing finished') 97 | pool.close() 98 | pool.join() 99 | # When only one core is asked, don't go to multiprocessing 100 | else: 101 | N = len(var_iterable) 102 | result = range(N) 103 | print('Starting process in only 1 core') 104 | for ind, elem in enumerate(var_iterable): 105 | result[ind] = function(elem, dict_constants) 106 | 107 | # Save and extract resultado 108 | self.resultado = result 109 | return result 110 | 111 | def method_single_proc(self, elem_iterable): 112 | # Method that is called in each iteration of the multiprocessing 113 | return self.external_function(elem_iterable, self.dict_constants) 114 | 115 | 116 | def execute_multiprocessing(__function_process__, 117 | dict_Parameters, 118 | num_processors, 119 | verbose: bool = False): 120 | """Executes multiprocessing reading a dictionary. 121 | 122 | Args: 123 | __function_process__ function tu process, it only accepts a dictionary 124 | dict_Parameters, dictionary / array with Args: 125 | num_processors, if 1 no multiprocessing is used 126 | verbose, prints processing time 127 | 128 | Returns: 129 | data: reults of multiprocessing 130 | processing time 131 | 132 | Examples: 133 | def __function_process__(xd): 134 | x = xd['x'] 135 | y = xd['y'] 136 | # grt = copy.deepcopy(grating) 137 | suma = x + y 138 | return dict(sumas=suma, ij=xd['ij']) 139 | 140 | def creation_dictionary_multiprocessing(): 141 | # create Args: for multiprocessing 142 | t1 = time.time() 143 | X = np.linspace(1, 2, 10) 144 | Y = np.linspace(1, 2, 1000) 145 | dict_Parameters = [] 146 | ij = 0 147 | for i, x in enumerate(X): 148 | for j, y in enumerate(Y): 149 | dict_Parameters.append(dict(x=x, y=y, ij=[ij])) 150 | ij += 1 151 | t2 = time.time() 152 | print("time creation dictionary = {}".format(t2 - t1)) 153 | return dict_Parameters 154 | """ 155 | t1 = time.time() 156 | if num_processors == 1 or len(dict_Parameters) < 2: 157 | data_pool = [__function_process__(xd) for xd in dict_Parameters] 158 | else: 159 | pool = multiprocessing.Pool(processes=num_processors) 160 | data_pool = pool.map(__function_process__, dict_Parameters) 161 | pool.close() 162 | pool.join() 163 | t2 = time.time() 164 | if verbose is True: 165 | print("num_proc: {}, time={}".format(num_processors, t2 - t1)) 166 | return data_pool, t2 - t1 167 | -------------------------------------------------------------------------------- /diffractio/utils_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: utils_tests.py 5 | # Purpose: Utility functions for testing operations 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | # flake8: noqa 15 | 16 | """ Common functions to classes """ 17 | 18 | import datetime 19 | import multiprocessing 20 | import sys 21 | import time 22 | 23 | from .utils_typing import NDArrayFloat 24 | 25 | from .__init__ import mm, no_date, np, plt, um 26 | from .scalar_masks_XY import Scalar_mask_XY 27 | 28 | max_num_cores = multiprocessing.cpu_count() 29 | min_num_pixels = 8 30 | max_num_pixels = 11 31 | 32 | NUM_CORES = np.array(list(range(1, max_num_cores + 1))) 33 | n = np.array(list(range(min_num_pixels, max_num_pixels))) 34 | NUM_PIXELS = 2**n 35 | NUM_PROCESSES = max_num_cores # 8 36 | 37 | if no_date is True: 38 | date = '0' 39 | else: 40 | now = datetime.datetime.now() 41 | date = now.strftime("%Y-%m-%d_%H") 42 | 43 | path_base = "tests_results" 44 | path_class = "utils_math" 45 | 46 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 47 | 48 | 49 | def _test_slit_RS_XY(num_pixels: int): 50 | """_test_slit_RS_XY 51 | 52 | Args: 53 | num_pixels (int): num_pixels 54 | 55 | Returns: 56 | u: field 57 | """ 58 | length = 512*um 59 | x = np.linspace(-length/2, length/2, num_pixels) 60 | y = np.linspace(-length/2, length/2, num_pixels) 61 | wavelength = 0.6328*um 62 | 63 | u1 = Scalar_mask_XY(x, y, wavelength) 64 | u1.slit(x0=0, size=25*um) 65 | u1.RS(z=1*mm, new_field=False, verbose=False) 66 | return u1 67 | 68 | 69 | def run_benchmark(num_pixels: int): 70 | """_summary_ 71 | 72 | Args: 73 | num_pixels (int): _description_ 74 | """ 75 | 76 | _test_slit_RS_XY(num_pixels=num_pixels) 77 | 78 | def test_pixels(self): 79 | func_name = sys._getframe().f_code.co_name 80 | # class_name = self.__class__.__name__ 81 | 82 | num_pixeles = 256 83 | time_array = benchmark_processors_n_pixels(num_pixeles) / NUM_PROCESSES 84 | 85 | plt.figure() 86 | plt.plot(NUM_CORES, time_array) 87 | plt.xlabel('num_cores') 88 | plt.ylabel('time_array') 89 | plt.title('num_pixels: {}, num_processes: {}'.format( 90 | str(num_pixeles), str(NUM_PROCESSES))) 91 | save_figure_test(newpath, func_name, '_time_numpixels') 92 | 93 | plt.figure() 94 | plt.plot(NUM_CORES, time_array[0] / time_array) 95 | plt.title('num_pixels: {}, num_processes: {}'.format( 96 | str(num_pixeles), str(NUM_PROCESSES))) 97 | plt.xlabel('num_cores') 98 | plt.ylabel('aceleracion') 99 | save_figure_test(newpath, func_name, '_acc') 100 | 101 | 102 | def comparison(proposal: NDArrayFloat, solution: NDArrayFloat, maximum_diff: float): 103 | """This functions is mainly for testing. It compares compares proposal to solution. 104 | 105 | Args: 106 | proposal (numpy.matrix): proposal of result. 107 | solution (numpy.matrix): results of the test. 108 | maximum_diff (float): maximum difference allowed. 109 | 110 | Returns: 111 | (bool): True if comparison is possitive, else False. 112 | """ 113 | 114 | comparison1 = np.linalg.norm(proposal - solution) < maximum_diff 115 | 116 | return comparison1 117 | 118 | 119 | def save_figure_test(newpath: str, func_name: str, add_name: str = ''): 120 | """_summary_ 121 | 122 | Args: 123 | newpath (str): _description_ 124 | func_name (str): _description_ 125 | add_name (str, optional): _description_. Defaults to ''. 126 | """ 127 | title = '{}{}'.format(func_name, add_name) 128 | plt.suptitle(title) 129 | filename = '{}{}{}.{}'.format(newpath, func_name, add_name, 'png') 130 | plt.savefig(filename) 131 | plt.close('all') 132 | 133 | 134 | def ejecute_multiprocessing(num_cores: int, n_pixels: int): 135 | """_summary_ 136 | 137 | Args: 138 | num_cores (int): _description_ 139 | n_pixels (int): _description_ 140 | """ 141 | num_pixeles = n_pixels * np.ones(NUM_PROCESSES) 142 | if num_cores == 1: 143 | [run_benchmark(i_pixels) for i_pixels in num_pixeles] 144 | else: 145 | pool = multiprocessing.Pool(processes=num_cores) 146 | pool.map(run_benchmark, num_pixeles) 147 | pool.close() 148 | pool.join() 149 | 150 | 151 | def benchmark_num_pixels(function, n_max: int = 10): 152 | """This function is for benchmarking using an increasing number of pixels 2**n. 153 | 154 | Args: 155 | function (function): Functions that has as argument the number of pixels 2**n. 156 | """ 157 | 158 | n = np.array(range(6, n_max + 1)) 159 | NUM_PIXELS = 2**n 160 | time_array = np.zeros_like(NUM_PIXELS, dtype='double') 161 | 162 | for n_pixels, i in zip(NUM_PIXELS, range(len(NUM_PIXELS))): 163 | t1 = time.time_ns()() 164 | function(num_data=n_pixels) 165 | t2 = time.time_ns() 166 | time_array[i] = (t2 - t1) * 1000 167 | print(n[i], n_pixels, t1, t2, time_array[i]) 168 | 169 | plt.figure() 170 | plt.plot(n, time_array, 'ko', ms=12) 171 | plt.figure() 172 | plt.plot(NUM_PIXELS, time_array / NUM_PIXELS, 'ko', ms=12) 173 | 174 | 175 | def benchmark_processors_n_pixels(n_pixels: int): 176 | """_summary_ 177 | 178 | Args: 179 | n_pixels (int): _description_ 180 | 181 | Returns: 182 | _type_: _description_ 183 | """ 184 | 185 | time_array = np.zeros_like(NUM_CORES, dtype='float') 186 | for i, core in enumerate(NUM_CORES): 187 | t1 = time.time() 188 | ejecute_multiprocessing(num_cores=core, n_pixels=n_pixels) 189 | t2 = time.time() 190 | time_array[i] = t2 - t1 191 | return time_array 192 | 193 | 194 | def save_data_test(cls, newpath: str, func_name: str, add_name: str = ''): 195 | """_summary_ 196 | 197 | Args: 198 | newpath (_type_): _description_ 199 | func_name (_type_): _description_ 200 | add_name (str, optional): _description_. Defaults to ''. 201 | """ 202 | 203 | filename = '{}{}{}.{}'.format(newpath, func_name, add_name, 'npz') 204 | print(filename) 205 | np.savez_compressed(file=filename, dict=cls.__dict__) 206 | -------------------------------------------------------------------------------- /diffractio/utils_typing.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | # ---------------------------------------------------------------------- 4 | # Name: utils_typing.py 5 | # Purpose: Utility functions for type annotations 6 | # 7 | # Author: Luis Miguel Sanchez Brea 8 | # 9 | # Created: 2024 10 | # Licence: GPLv3 11 | # ---------------------------------------------------------------------- 12 | 13 | 14 | 15 | # https://docs.python.org/3/library/typing.html 16 | # https://numpy.org/devdocs/reference/typing.html 17 | 18 | 19 | import numpy as np 20 | from typing import Any, List, Literal 21 | import numpy.typing as npt 22 | 23 | 24 | NDArray = npt.NDArray 25 | NDArrayInt = npt.NDArray[np.integer] 26 | NDArrayFloat = npt.NDArray[np.floating] 27 | NDArrayComplex = npt.NDArray[np.complexfloating] 28 | integer = np.integer 29 | 30 | 31 | # Para 3.12 o posterior, es decir, es muy nuevo 32 | # type point2D = tuple[float, float] | NDArray 33 | 34 | # some temporal helps 35 | """ 36 | type Vector = tuple[float] 37 | type ConnectionOptions = dict[str, str] 38 | type Address = tuple[str, int] 39 | type Server = tuple[Address, ConnectionOptions] 40 | 41 | np.array(x**2 for x in range(10)) # type: ignoref 42 | 43 | from typing import NewType 44 | 45 | UserId = NewType('UserId', int) 46 | some_id = UserId(524313) 47 | tuple[int, str] 48 | tuple[int] = (1, 2, 3) 49 | tuple[int, ...] = (1, 2) 50 | 51 | clases 52 | def make_new_user(user_class: type[User]) -> User: 53 | 54 | from typing import NoReturn 55 | 56 | def stop() -> NoReturn: 57 | raise RuntimeError('no way') 58 | """ 59 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python3 -msphinx 7 | SPHINXPROJ = diffractio 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/_static -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # diffractio documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another 17 | # directory, add these directories to sys.path here. If the directory is 18 | # relative to the documentation root, use os.path.abspath to make it 19 | # absolute, like shown here. 20 | # 21 | import os 22 | import sys 23 | 24 | sys.path.insert(0, os.path.abspath('..')) 25 | 26 | # -- General configuration --------------------------------------------------------- 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | # 30 | # needs_sphinx = '1.0' 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 34 | # extensions = [ 35 | # 'sphinx.ext.autodoc', 36 | # 'sphinx.ext.viewcode', 37 | # ] 38 | 39 | extensions = [ 40 | 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.mathjax', 41 | 'sphinx.ext.napoleon', 'nbsphinx', 'sphinx.ext.todo' 42 | ] 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ['_templates'] 46 | 47 | # The suffix(es) of source filenames. 48 | # You can specify multiple suffix as a list of string: 49 | # 50 | source_suffix = ['.rst', '.md'] 51 | # source_suffix = ['.rst', '.md', '.ipynb'] 52 | 53 | # The master toctree document. 54 | master_doc = 'index' 55 | 56 | # General information about the project. 57 | project = u'Python diffraction and interference' 58 | copyright = u"2019, Luis Miguel Sanchez Brea" 59 | author = u"Luis Miguel Sanchez Brea" 60 | 61 | # The version info for the project you're documenting, acts as replacement 62 | # for |version| and |release|, also used in various other places throughout 63 | # the built documents. 64 | # 65 | # The short X.Y version. 66 | # version = diffractio.__version__ 67 | version = '0.3.1' 68 | # The full version, including alpha/beta/rc tags. 69 | # release = diffractio.__version__ 70 | release = version 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | # 75 | # This is also used if you do content translation via gettext catalogs. 76 | # Usually you set "language" from the command line for these cases. 77 | language = 'en' 78 | 79 | # List of patterns, relative to source directory, that match files and 80 | # directories to ignore when looking for source files. 81 | # This patterns also effect to html_static_path and html_extra_path 82 | exclude_patterns = [ 83 | '_build', 'Thumbs.db', '.DS_Store', '_build', '**.ipynb_checkpoints' 84 | ] 85 | # LM: exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 86 | # The name of the Pygments (syntax highlighting) style to use. 87 | pygments_style = 'sphinx' 88 | 89 | # If true, `todo` and `todoList` produce output, else they produce nothing. 90 | todo_include_todos = False 91 | 92 | # -- Options for HTML output ------------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | # 97 | # html_theme = 'alabaster' 98 | html_theme = "sphinx_rtd_theme" 99 | # Theme options are theme-specific and customize the look and feel of a 100 | # theme further. For a list of options available for each theme, see the 101 | # documentation. 102 | # 103 | # html_theme_options = {} 104 | 105 | # Add any paths that contain custom static files (such as style sheets) here, 106 | # relative to this directory. They are copied after the builtin static files, 107 | # so a file named "default.css" will overwrite the builtin "default.css". 108 | html_static_path = ['_static'] 109 | 110 | # -- Options for HTMLHelp output --------------------------------------------------- 111 | 112 | # Output file base name for HTML help builder. 113 | htmlhelp_basename = 'diffractiodoc' 114 | 115 | # -- Options for LaTeX output ------------------------------------------------------ 116 | 117 | latex_elements = { 118 | # The paper size ('letterpaper' or 'a4paper'). 119 | # 120 | # 'papersize': 'letterpaper', 121 | 122 | # The font size ('10pt', '11pt' or '12pt'). 123 | # 124 | # 'pointsize': '10pt', 125 | 126 | # Additional stuff for the LaTeX preamble. 127 | # 128 | # 'preamble': '', 129 | 130 | # Latex figure (float) alignment 131 | # 132 | # 'figure_align': 'htbp', 133 | } 134 | 135 | # Grouping the document tree into LaTeX files. List of tuples 136 | # (source start file, target name, title, author, documentclass 137 | # [howto, manual, or own class]). 138 | latex_documents = [ 139 | (master_doc, 'diffractio.tex', 140 | u'Python diffraction and interference Documentation', 141 | u'Luis Miguel Sanchez Brea', 'manual'), 142 | ] 143 | 144 | # -- Options for manual page output ------------------------------------------------ 145 | 146 | # One entry per manual page. List of tuples 147 | # (source start file, name, description, authors, manual section). 148 | man_pages = [(master_doc, 'diffractio', 149 | u'Python diffraction and interference Documentation', [author 150 | ], 1)] 151 | 152 | # -- Options for Texinfo output ---------------------------------------------------- 153 | 154 | # Grouping the document tree into Texinfo files. List of tuples 155 | # (source start file, target name, title, author, 156 | # dir menu entry, description, category) 157 | texinfo_documents = [ 158 | (master_doc, 'diffractio', 159 | u'Python diffraction and interference Documentation', author, 160 | 'diffractio'), 161 | ] 162 | 163 | # Module items sort order 164 | autodoc_member_order = 'bysource' 165 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/diffractio.rst: -------------------------------------------------------------------------------- 1 | diffractio package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | diffractio.config module 8 | ------------------------ 9 | 10 | .. automodule:: diffractio.config 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | diffractio.scalar\_fields\_X module 16 | ----------------------------------- 17 | 18 | .. automodule:: diffractio.scalar_fields_X 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | diffractio.scalar\_fields\_XY module 24 | ------------------------------------ 25 | 26 | .. automodule:: diffractio.scalar_fields_XY 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | diffractio.scalar\_fields\_XYZ module 32 | ------------------------------------- 33 | 34 | .. automodule:: diffractio.scalar_fields_XYZ 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | diffractio.scalar\_fields\_XZ module 40 | ------------------------------------ 41 | 42 | .. automodule:: diffractio.scalar_fields_XZ 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | diffractio.scalar\_fields\_Z module 48 | ----------------------------------- 49 | 50 | .. automodule:: diffractio.scalar_fields_Z 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | diffractio.scalar\_masks\_X module 56 | ---------------------------------- 57 | 58 | .. automodule:: diffractio.scalar_masks_X 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | diffractio.scalar\_masks\_XY module 64 | ----------------------------------- 65 | 66 | .. automodule:: diffractio.scalar_masks_XY 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | diffractio.scalar\_masks\_XYZ module 72 | ------------------------------------ 73 | 74 | .. automodule:: diffractio.scalar_masks_XYZ 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | diffractio.scalar\_masks\_XZ module 80 | ----------------------------------- 81 | 82 | .. automodule:: diffractio.scalar_masks_XZ 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | diffractio.scalar\_sources\_X module 88 | ------------------------------------ 89 | 90 | .. automodule:: diffractio.scalar_sources_X 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | 95 | diffractio.scalar\_sources\_XY module 96 | ------------------------------------- 97 | 98 | .. automodule:: diffractio.scalar_sources_XY 99 | :members: 100 | :undoc-members: 101 | :show-inheritance: 102 | 103 | diffractio.utils\_common module 104 | ------------------------------- 105 | 106 | .. automodule:: diffractio.utils_common 107 | :members: 108 | :undoc-members: 109 | :show-inheritance: 110 | 111 | diffractio.utils\_drawing module 112 | -------------------------------- 113 | 114 | .. automodule:: diffractio.utils_drawing 115 | :members: 116 | :undoc-members: 117 | :show-inheritance: 118 | 119 | diffractio.utils\_drawing3D module 120 | ---------------------------------- 121 | 122 | .. automodule:: diffractio.utils_drawing3D 123 | :members: 124 | :undoc-members: 125 | :show-inheritance: 126 | 127 | diffractio.utils\_dxf module 128 | ---------------------------- 129 | 130 | .. automodule:: diffractio.utils_dxf 131 | :members: 132 | :undoc-members: 133 | :show-inheritance: 134 | 135 | diffractio.utils\_math module 136 | ----------------------------- 137 | 138 | .. automodule:: diffractio.utils_math 139 | :members: 140 | :undoc-members: 141 | :show-inheritance: 142 | 143 | diffractio.utils\_multiprocessing module 144 | ---------------------------------------- 145 | 146 | .. automodule:: diffractio.utils_multiprocessing 147 | :members: 148 | :undoc-members: 149 | :show-inheritance: 150 | 151 | diffractio.utils\_optics module 152 | ------------------------------- 153 | 154 | .. automodule:: diffractio.utils_optics 155 | :members: 156 | :undoc-members: 157 | :show-inheritance: 158 | 159 | diffractio.utils\_tests module 160 | ------------------------------ 161 | 162 | .. automodule:: diffractio.utils_tests 163 | :members: 164 | :undoc-members: 165 | :show-inheritance: 166 | 167 | diffractio.utils\_typing module 168 | ------------------------------- 169 | 170 | .. automodule:: diffractio.utils_typing 171 | :members: 172 | :undoc-members: 173 | :show-inheritance: 174 | 175 | diffractio.vector\_fields\_X module 176 | ----------------------------------- 177 | 178 | .. automodule:: diffractio.vector_fields_X 179 | :members: 180 | :undoc-members: 181 | :show-inheritance: 182 | 183 | diffractio.vector\_fields\_XY module 184 | ------------------------------------ 185 | 186 | .. automodule:: diffractio.vector_fields_XY 187 | :members: 188 | :undoc-members: 189 | :show-inheritance: 190 | 191 | diffractio.vector\_fields\_XYZ module 192 | ------------------------------------- 193 | 194 | .. automodule:: diffractio.vector_fields_XYZ 195 | :members: 196 | :undoc-members: 197 | :show-inheritance: 198 | 199 | diffractio.vector\_fields\_XZ module 200 | ------------------------------------ 201 | 202 | .. automodule:: diffractio.vector_fields_XZ 203 | :members: 204 | :undoc-members: 205 | :show-inheritance: 206 | 207 | diffractio.vector\_fields\_Z module 208 | ----------------------------------- 209 | 210 | .. automodule:: diffractio.vector_fields_Z 211 | :members: 212 | :undoc-members: 213 | :show-inheritance: 214 | 215 | diffractio.vector\_masks\_XY module 216 | ----------------------------------- 217 | 218 | .. automodule:: diffractio.vector_masks_XY 219 | :members: 220 | :undoc-members: 221 | :show-inheritance: 222 | 223 | diffractio.vector\_sources\_XY module 224 | ------------------------------------- 225 | 226 | .. automodule:: diffractio.vector_sources_XY 227 | :members: 228 | :undoc-members: 229 | :show-inheritance: 230 | 231 | Module contents 232 | --------------- 233 | 234 | .. automodule:: diffractio 235 | :members: 236 | :undoc-members: 237 | :show-inheritance: 238 | -------------------------------------------------------------------------------- /docs/examples_scalar.rst: -------------------------------------------------------------------------------- 1 | Examples for scalar propagation 2 | ==================================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | 10 | source/examples_scalar/far_near_field.ipynb 11 | source/examples_scalar/gauss_beam.ipynb 12 | source/examples_scalar/reflection_refraction.ipynb 13 | source/examples_scalar/lenses.ipynb 14 | source/examples_scalar/arago_point.ipynb 15 | source/examples_scalar/diffraction_slit.ipynb 16 | source/examples_scalar/diffraction_objects.ipynb 17 | source/examples_scalar/scattering_small_cylinders.ipynb 18 | source/examples_scalar/fresnel_biprism.ipynb 19 | source/examples_scalar/fresnel_lens.ipynb 20 | source/examples_scalar/focal_shift.ipynb 21 | source/examples_scalar/photon_sieve.ipynb 22 | source/examples_scalar/talbot_effect.ipynb 23 | source/examples_scalar/blazed_grating.ipynb 24 | source/examples_scalar/dammann.ipynb 25 | source/examples_scalar/dobule_grating.ipynb 26 | source/examples_scalar/variable_refractive_index.ipynb 27 | source/examples_scalar/image_formation.ipynb 28 | -------------------------------------------------------------------------------- /docs/examples_vector.rst: -------------------------------------------------------------------------------- 1 | Examples for vector propagation 2 | ==================================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | 10 | source/examples_vector/gauss_beam.ipynb 11 | source/examples_vector/reflection_refraction.ipynb 12 | source/examples_vector/diffraction_slit.ipynb 13 | source/examples_vector/diffraction_objects.ipynb 14 | source/examples_vector/lens.ipynb 15 | source/examples_vector/VRS_paper.ipynb 16 | source/examples_vector/vector_double_slit_experiment.ipynb 17 | source/examples_vector/SLM.ipynb 18 | source/examples_vector/malus_law.ipynb 19 | source/examples_vector/vector FPZ.ipynb 20 | source/examples_vector/vector_grating_xy.ipynb 21 | source/examples_vector/vector_grating_xz.ipynb 22 | 23 | -------------------------------------------------------------------------------- /docs/files_jupyter.rst: -------------------------------------------------------------------------------- 1 | Jupyter files 2 | ================================ 3 | 4 | - BPM.ipynb: 363 lines 5 | - CZT.ipynb: 806 lines 6 | - CZT_vs_RS.ipynb: 555 lines 7 | - FFT.ipynb: 394 lines 8 | - PWD.ipynb: 451 lines 9 | - RS.ipynb: 537 lines 10 | - RS_vs_WPM.ipynb: 251 lines 11 | - SLM.ipynb: 727 lines 12 | - VCZT.ipynb: 554 lines 13 | - VCZT_vs_VRS.ipynb: 277 lines 14 | - VFFT.ipynb: 321 lines 15 | - VRS.ipynb: 296 lines 16 | - VRS_paper.ipynb: 616 lines 17 | - WPM.ipynb: 371 lines 18 | - WPM_vs_BPM.ipynb: 773 lines 19 | - WPM_ws.ipynb: 741 lines 20 | - add_fields.ipynb: 667 lines 21 | - arago_point.ipynb: 545 lines 22 | - artifacts_bpm.ipynb: 516 lines 23 | - blazed_grating.ipynb: 326 lines 24 | - creating_video.ipynb: 393 lines 25 | - dammann.ipynb: 354 lines 26 | - developing_new_functions.ipynb: 229 lines 27 | - diffraction_objects.ipynb: 1171 lines 28 | - diffraction_slit.ipynb: 409 lines 29 | - diffraction_slit.ipynb: 600 lines 30 | - double_grating.ipynb: 283 lines 31 | - drawing_xz.ipynb: 655 lines 32 | - dxf_XY.ipynb: 367 lines 33 | - dxf_XZ.ipynb: 270 lines 34 | - external_qt.ipynb: 525 lines 35 | - far_near_field.ipynb: 276 lines 36 | - focal_shift.ipynb: 269 lines 37 | - fresnel_biprism.ipynb: 539 lines 38 | - fresnel_equations.ipynb: 559 lines 39 | - fresnel_lens.ipynb: 564 lines 40 | - gauss_beam.ipynb: 323 lines 41 | - gauss_beam.ipynb: 700 lines 42 | - has_edges.ipynb: 305 lines 43 | - image_formation.ipynb: 405 lines 44 | - interactive_in_diffractio.ipynb: 218 lines 45 | - lens.ipynb: 793 lines 46 | - lenses.ipynb: 1397 lines 47 | - logarithm.ipynb: 307 lines 48 | - malus_law.ipynb: 242 lines 49 | - masks_x.ipynb: 1133 lines 50 | - masks_xy.ipynb: 1889 lines 51 | - masks_xy_procedures.ipynb: 692 lines 52 | - masks_xyz.ipynb: 310 lines 53 | - masks_xz.ipynb: 1196 lines 54 | - masks_xz_procedures.ipynb: 955 lines 55 | - multiprocessing.ipynb: 1204 lines 56 | - oversampling_xy.ipynb: 306 lines 57 | - phase_intensity.ipynb: 269 lines 58 | - photon_sieve.ipynb: 240 lines 59 | - power_z_propagation.ipynb: 194 lines 60 | - quality_factor.ipynb: 576 lines 61 | - reflection_refraction.ipynb: 582 lines 62 | - reflection_refraction.ipynb: 659 lines 63 | - scalar_field_z.ipynb: 314 lines 64 | - scattering_small_cylinders.ipynb: 241 lines 65 | - sources_x.ipynb: 433 lines 66 | - sources_xy.ipynb: 887 lines 67 | - surfaces.ipynb: 498 lines 68 | - talbot_effect.ipynb: 761 lines 69 | - tutorial_vector_XY.ipynb: 1032 lines 70 | - tutorial_vector_XYZ.ipynb: 396 lines 71 | - tutorial_vector_XY_draw.ipynb: 410 lines 72 | - tutorial_vector_XZ.ipynb: 725 lines 73 | - tutorial_vector_masks_XY.ipynb: 583 lines 74 | - tutorial_vector_sources_XY.ipynb: 1235 lines 75 | - tutorial_x.ipynb: 1137 lines 76 | - tutorial_xy.ipynb: 749 lines 77 | - tutorial_xyz.ipynb: 783 lines 78 | - tutorial_xz.ipynb: 2043 lines 79 | - use_interact_visualize_profiles.ipynb: 521 lines 80 | - variable_refractive_index.ipynb: 594 lines 81 | - vector FPZ.ipynb: 298 lines 82 | - vector grating xz.ipynb: 374 lines 83 | - vector_double_slit_experiment.ipynb: 480 lines 84 | - vector_grating_xy.ipynb: 782 lines 85 | - wpm-bpm 3d.ipynb: 427 lines 86 | - wpm_without_storing.ipynb: 398 lines 87 | 88 | Total number of lines in Python files: 48546 89 | -------------------------------------------------------------------------------- /docs/files_python.rst: -------------------------------------------------------------------------------- 1 | Python files 2 | ================================ 3 | 4 | - conf.py: 164 lines 5 | - config.py: 66 lines 6 | - count_number_lines.py: 69 lines 7 | - diffractio.py: 181 lines 8 | - get_functions.py: 125 lines 9 | - scalar_fields_X.py: 1737 lines 10 | - scalar_fields_XY.py: 2824 lines 11 | - scalar_fields_XYZ.py: 1579 lines 12 | - scalar_fields_XZ.py: 2086 lines 13 | - scalar_fields_Z.py: 487 lines 14 | - scalar_masks_X.py: 978 lines 15 | - scalar_masks_XY.py: 2659 lines 16 | - scalar_masks_XYZ.py: 265 lines 17 | - scalar_masks_XZ.py: 1470 lines 18 | - scalar_sources_X.py: 222 lines 19 | - scalar_sources_XY.py: 562 lines 20 | - setup.py: 64 lines 21 | - test_scalar_fields_X.py: 394 lines 22 | - test_scalar_fields_XY.py: 750 lines 23 | - test_scalar_fields_XZ.py: 920 lines 24 | - test_scalar_fields_X_multiprocessing.py: 462 lines 25 | - test_scalar_masks_X.py: 515 lines 26 | - test_scalar_masks_XY.py: 1068 lines 27 | - test_scalar_masks_XYZ.py: 63 lines 28 | - test_scalar_masks_XZ.py: 683 lines 29 | - test_scalar_sources_X.py: 210 lines 30 | - test_scalar_sources_XY.py: 565 lines 31 | - test_utils_math.py: 182 lines 32 | - test_utils_multiprocessing.py: 59 lines 33 | - test_vector_draw_XY.py: 98 lines 34 | - test_vector_fields_XY.py: 232 lines 35 | - test_vector_masks_XY.py: 198 lines 36 | - test_vector_sources_XY.py: 259 lines 37 | - utils_common.py: 596 lines 38 | - utils_drawing.py: 482 lines 39 | - utils_drawing3D.py: 535 lines 40 | - utils_dxf.py: 187 lines 41 | - utils_math.py: 982 lines 42 | - utils_multiprocessing.py: 166 lines 43 | - utils_optics.py: 1228 lines 44 | - utils_tests.py: 205 lines 45 | - utils_typing.py: 58 lines 46 | - vector_fields_X.py: 673 lines 47 | - vector_fields_XY.py: 2251 lines 48 | - vector_fields_XYZ.py: 892 lines 49 | - vector_fields_XZ.py: 2123 lines 50 | - vector_fields_Z.py: 625 lines 51 | - vector_masks_XY.py: 732 lines 52 | - vector_sources_XY.py: 422 lines 53 | 54 | Total number of lines in Python files: 34353 55 | -------------------------------------------------------------------------------- /docs/functioning.rst: -------------------------------------------------------------------------------- 1 | About functiong 2 | ========================== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | :numbered: 8 | :glob: 9 | 10 | source/functioning/developing_new_functions.ipynb 11 | source/functioning/surfaces.ipynb 12 | source/functioning/artifacts_bpm.ipynb 13 | source/functioning/multiprocessing.ipynb 14 | source/functioning/power_z_propagation.ipynb 15 | source/functioning/phase_intensity.ipynb 16 | source/functioning/quality_factor.ipynb 17 | source/functioning/WPM_ws.ipynb 18 | source/functioning/has_edges.ipynb 19 | source/functioning/dxf_XY.ipynb 20 | source/functioning/dxf_XZ.ipynb 21 | source/functioning/add_fields.ipynb 22 | source/functioning/oversampling_xy.ipynb 23 | source/functioning/backpropagation.ipynb 24 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Diffractio: Python diffraction and interference's documentation! 2 | =================================================================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | :numbered: 8 | :glob: 9 | 10 | readme 11 | installation 12 | usage 13 | modules 14 | new 15 | tutorials_scalar 16 | tutorials_vector 17 | examples_scalar 18 | examples_vector 19 | functioning 20 | contributing 21 | authors 22 | references 23 | statistics 24 | history 25 | todo 26 | 27 | Indices and tables 28 | ================== 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | 8 | Stable release 9 | -------------- 10 | 11 | To install Python diffraction and interference, run this command in your terminal: 12 | 13 | .. code-block:: console 14 | 15 | # Linux: 16 | $ pip3 install diffractio 17 | 18 | # Windows: 19 | $ pip install diffractio 20 | 21 | 22 | This is the preferred method to install Python diffraction and interference, as it will always install the most recent stable release. 23 | 24 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide 25 | you through the process. 26 | 27 | .. _pip: https://pip.pypa.io 28 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ 29 | 30 | 31 | Additional packages 32 | ------------------------ 33 | 34 | Diffractio uses also the following non-standard modules: 35 | 36 | * py-pol 37 | 38 | In some schemes, the following modules are also required: 39 | 40 | * numpy, scipy, matplotlib 41 | * Pillow, numexpr, pandas, screeninfo, opencv-python 42 | * ipywidgets, ipympl 43 | * Pyvista 44 | 45 | They should previously be installed before Diffractio module. 46 | 47 | 48 | From sources 49 | ------------ 50 | 51 | The sources for Python diffraction and interference can be downloaded from the `Github repo`_. 52 | 53 | You can either clone the public repository: 54 | 55 | .. code-block:: console 56 | 57 | $ git clone https://github.com/optbrea/diffractio.git 58 | $ git clone git@github.com:optbrea/diffractio.git 59 | 60 | 61 | 62 | Once you have a copy of the source, you can install it with: 63 | 64 | .. code-block:: console 65 | 66 | # Linux: 67 | $ python3 setup.py install 68 | 69 | # Windows: 70 | $ python setup.py install 71 | 72 | 73 | 74 | .. _Github repo: https://github.com/optbrea/diffractio 75 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/logo.png -------------------------------------------------------------------------------- /docs/logoUCM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/logoUCM.png -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python3 -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=diffractio 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | diffractio 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | diffractio 8 | -------------------------------------------------------------------------------- /docs/new.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../NEW.rst 2 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /docs/readme1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme1.png -------------------------------------------------------------------------------- /docs/readme10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme10.png -------------------------------------------------------------------------------- /docs/readme2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme2.png -------------------------------------------------------------------------------- /docs/readme3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme3.png -------------------------------------------------------------------------------- /docs/readme4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme4.png -------------------------------------------------------------------------------- /docs/readme5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme5.png -------------------------------------------------------------------------------- /docs/readme6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme6.png -------------------------------------------------------------------------------- /docs/readme7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme7.png -------------------------------------------------------------------------------- /docs/readme8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme8.png -------------------------------------------------------------------------------- /docs/readme9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/readme9.png -------------------------------------------------------------------------------- /docs/references.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../REFERENCES.rst 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Defining the exact version will make sure things don't break 2 | # sphinx==5.3.0 3 | # sphinx_rtd_theme==1.1.1 4 | # readthedocs-sphinx-search==0.1.1 5 | 6 | # Defining the exact version will make sure things don't break 7 | 8 | 9 | 10 | sphinx>=1.4 11 | ipykernel 12 | nbsphinx 13 | sphinx_rtd_theme 14 | readthedocs-sphinx-search -------------------------------------------------------------------------------- /docs/results.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../RESULTS.rst 2 | -------------------------------------------------------------------------------- /docs/source/README.txt: -------------------------------------------------------------------------------- 1 | .. _tutorials: 2 | 3 | Tutorials 4 | ========= 5 | 6 | This page contains more in-depth guides for using diffractio. 7 | It is broken up into beginner, intermediate, and advanced sections, 8 | as well as sections covering specific topics. 9 | -------------------------------------------------------------------------------- /docs/source/examples_scalar/USAF-1951-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/examples_scalar/USAF-1951-1024.png -------------------------------------------------------------------------------- /docs/source/examples_scalar/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/examples_scalar/fig1.png -------------------------------------------------------------------------------- /docs/source/examples_scalar/lenaColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/examples_scalar/lenaColor.png -------------------------------------------------------------------------------- /docs/source/examples_scalar/qt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/examples_scalar/qt.png -------------------------------------------------------------------------------- /docs/source/examples_vector/calibration_slm_jones_2500.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/examples_vector/calibration_slm_jones_2500.npz -------------------------------------------------------------------------------- /docs/source/functioning/qt2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/functioning/qt2.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/algorithms/tutorial.rst: -------------------------------------------------------------------------------- 1 | Algorithms 2 | ============= 3 | 4 | Propagation algorithms is a fundamental key in Diffractio package. The algorithms implemented for scalar propagation are: 5 | 6 | * Fast Fourier Transform (FFT). 7 | * Rayleigh Sommerfeld (RS). 8 | * Plane Wave Descomposition (PWD). 9 | * Beam Propagation Method (BPM). 10 | * Wave Propagation Method (WPM). 11 | * Chirp z-transform (CZT). 12 | 13 | 14 | **Fast Fourier Transform (FFT)** 15 | 16 | It allows, in a single step to determine the field at the far field. 17 | The fields and the masks must be defined in a plane. 18 | 19 | 20 | **Rayleigh-Sommerfeld (RS)** 21 | - Shen, F., and Wang, A. (2006). Fast-Fourier-transform based numerical integration method for the Rayleigh-Sommerfeld diffraction formula. Applied Optics, 45(6), 1102–1110. https://doi.org/10.1364/AO.45.001102 22 | 23 | Single step to propagate to a near or far observation plane, which allows fast computations. 24 | 25 | **Plane Wave Descomposition (PWD)** 26 | - It is implemented as it is required for some other algorithms, although it is recommended to use the WPM algorithm. 27 | 28 | 29 | **Beam propagation method (BPM)** 30 | 31 | - Feit, M. D., and Fleck, J. A. (1978). Light propagation in graded-index optical fibers. 32 | 33 | Propation of light in volumetric elements, provided that the spatial variations in the refractive index are small. It allows graded index structures. It presents a complexity of O(n) in the two-dimensional and O(n2) in the three-dimensional case. Computed according to split-step propagation scheme. 34 | 35 | 36 | **Wave Propagation Method (WPM)** 37 | 38 | - Brenner, K.-H. H., and Singer, W. (1993). Light propagation through microlenses: a new simulation method. Applied Optics, 32(26), 4984–4988. https://doi.org/10.1364/ao.32.004984 39 | 40 | - Brenner, K. H. (2017). A high-speed version of the wave propagation method applied to micro-optics. 2017 16th Workshop on Information Optics, WIO 2017, 1, 2–4. https://doi.org/10.1109/WIO.2017.8038108 41 | 42 | - Schmidt, S., Thiele, S., Herkommer, A., Tünnermann, A., and Gross, H. (2017). Rotationally symmetric formulation of the wave propagation method-application to the straylight analysis of diffractive lenses. Optics Letters, 42(8), 1612. https://doi.org/10.1364/ol.42.001612 43 | 44 | Solves the major limitations of the beam propagation method (BPM). The wave propagation scheme provides valid results for propagation angles up to 85° and that it is not limited to small index variations in the axis of propagation. Very fast with a discrete number of refractive indexes. 45 | 46 | 47 | **Chirped z Transform (CZT)** 48 | 49 | - Leutenegger, M., Rao, R., Leitgeb, R. A., and Lasser, T. (2006). Fast focus field calculations. Optics Express, 14(23), 11277–11291. http://lob.epfl.ch/ 50 | 51 | - Hu, Y., Wang, Z., Wang, X., Ji, S., Zhang, C., Li, J., Zhu, W., Wu, D., and Chu, J. (2020). Efficient full-path optical calculation of scalar and vector diffraction using the Bluestein method. Light: Science and Applications, 9(1). https://doi.org/10.1038/s41377-020-00362-z 52 | 53 | 54 | .. toctree:: 55 | :maxdepth: 2 56 | :numbered: 57 | :glob: 58 | 59 | 60 | FFT.ipynb 61 | RS.ipynb 62 | PWD.ipynb 63 | CZT.ipynb 64 | BPM.ipynb 65 | WPM.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/comparison/tutorial.rst: -------------------------------------------------------------------------------- 1 | Comparison between algorithms 2 | ======================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | :numbered: 7 | :glob: 8 | 9 | RS_vs_WPM.ipynb 10 | WPM_vs_BPM.ipynb 11 | CZT_vs_RS.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/creating_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/drawing/creating_video.mp4 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/interactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/drawing/interactive.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/interactive2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/drawing/interactive2.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/qt_propagation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/drawing/qt_propagation.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/tutorial.rst: -------------------------------------------------------------------------------- 1 | Some info about drawing and videos 2 | ======================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | logarithm.ipynb 10 | creating_video.ipynb 11 | use_interact_visualize_profiles.ipynb 12 | interactive_in_diffractio.ipynb 13 | external_qt.ipynb 14 | -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/drawing/video_circle.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/drawing/video_circle.mp4 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/other/tutorial.rst: -------------------------------------------------------------------------------- 1 | Other cases 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | fresnel_equations.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_X/profile1.txt: -------------------------------------------------------------------------------- 1 | -13 -2.7377 2 | -12.5 -5.3664 3 | -12 -6.7107 4 | -11.5 -7.6529 5 | -11 -8.3366 6 | -10.5 -8.8504 7 | -10 -9.3111 8 | -9.5 -9.6747 9 | -9 -9.9809 10 | -8.5 -10.2391 11 | -8 -10.4564 12 | -7.5 -10.6546 13 | -7 -10.786 14 | -6.5 -10.9072 15 | -6 -11.0022 16 | -5.5 -11.0741 17 | -5 -11.1238 18 | -4.5 -11.1711 19 | -4 -11.1711 20 | -3.5 -11.172 21 | -3 -11.1594 22 | -2.5 -11.1366 23 | -2 -11.1043 24 | -1.5 -11.0755 25 | -1 -11.0454 26 | -0.5 -11.0269 27 | 0 -11.02 28 | 0.5 -11.0269 29 | 1 -11.0454 30 | 1.5 -11.0755 31 | 2 -11.1043 32 | 2.5 -11.1366 33 | 3 -11.1594 34 | 3.5 -11.172 35 | 4 -11.1711 36 | 4.5 -11.1711 37 | 5 -11.1238 38 | 5.5 -11.0741 39 | 6 -11.0022 40 | 6.5 -10.9072 41 | 7 -10.786 42 | 7.5 -10.6546 43 | 8 -10.4564 44 | 8.5 -10.2391 45 | 9 -9.9809 46 | 9.5 -9.6747 47 | 10 -9.3111 48 | 10.5 -8.8504 49 | 11 -8.3366 50 | 11.5 -7.6529 51 | 12 -6.7107 52 | 12.5 -5.3664 53 | 13 -2.7377 54 | -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_X/profile2.txt: -------------------------------------------------------------------------------- 1 | -11.5 -0.1014 2 | -11 -0.9674 3 | -10.5 -1.8335 4 | -10 -2.6995 5 | -9.5 -3.5655 6 | -9 -4.4315 7 | -8.5 -5.2878 8 | -8 -6.02 9 | -7.5 -6.6344 10 | -7 -7.1614 11 | -6.5 -7.6193 12 | -6 -8.02 13 | -5.5 -8.3716 14 | -5 -8.6803 15 | -4.5 -8.9503 16 | -4 -9.1852 17 | -3.5 -9.3875 18 | -3 -9.5594 19 | -2.5 -9.7025 20 | -2 -9.818 21 | -1.5 -9.9069 22 | -1 -9.9699 23 | -0.5 -10.0075 24 | 0 -10.02 25 | 0.5 -10.0075 26 | 1 -9.9699 27 | 1.5 -9.9069 28 | 2 -9.818 29 | 2.5 -9.7025 30 | 3 -9.5594 31 | 3.5 -9.3875 32 | 4 -9.1852 33 | 4.5 -8.9503 34 | 5 -8.6803 35 | 5.5 -8.3716 36 | 6 -8.02 37 | 6.5 -7.6193 38 | 7 -7.1614 39 | 7.5 -6.6344 40 | 8 -6.02 41 | 8.5 -5.2878 42 | 9 -4.4315 43 | 9.5 -3.5655 44 | 10 -2.6995 45 | 10.5 -1.8335 46 | 11 -0.9674 47 | 11.5 -0.1014 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_X/save_load.hkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_X/save_load.hkl -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_X/save_load.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_X/save_load.npz -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_X/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_X 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_x.ipynb 10 | sources_x.ipynb 11 | masks_x.ipynb 12 | -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XY/save_load.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XY/save_load.npz -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XY/spain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XY/spain.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XY/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_XY 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_xy.ipynb 10 | sources_xy.ipynb 11 | masks_xy.ipynb 12 | masks_xy_procedures.ipynb 13 | -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XYZ/save_load_xyz.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XYZ/save_load_xyz.npz -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XYZ/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_XYZ 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_xyz.ipynb 10 | 11 | wpm-bpm 3d.ipynb 12 | 13 | wpm_without_storing.ipynb 14 | 15 | masks_xyz.ipynb 16 | 17 | masks_xyz_procedures.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XYZ/video_RS_int.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XYZ/video_RS_int.mp4 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/creating_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/creating_video.mp4 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/detection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/detection.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/profile.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/profile1.txt: -------------------------------------------------------------------------------- 1 | -13 -2.7377 2 | -12.5 -5.3664 3 | -12 -6.7107 4 | -11.5 -7.6529 5 | -11 -8.3366 6 | -10.5 -8.8504 7 | -10 -9.3111 8 | -9.5 -9.6747 9 | -9 -9.9809 10 | -8.5 -10.2391 11 | -8 -10.4564 12 | -7.5 -10.6546 13 | -7 -10.786 14 | -6.5 -10.9072 15 | -6 -11.0022 16 | -5.5 -11.0741 17 | -5 -11.1238 18 | -4.5 -11.1711 19 | -4 -11.1711 20 | -3.5 -11.172 21 | -3 -11.1594 22 | -2.5 -11.1366 23 | -2 -11.1043 24 | -1.5 -11.0755 25 | -1 -11.0454 26 | -0.5 -11.0269 27 | 0 -11.02 28 | 0.5 -11.0269 29 | 1 -11.0454 30 | 1.5 -11.0755 31 | 2 -11.1043 32 | 2.5 -11.1366 33 | 3 -11.1594 34 | 3.5 -11.172 35 | 4 -11.1711 36 | 4.5 -11.1711 37 | 5 -11.1238 38 | 5.5 -11.0741 39 | 6 -11.0022 40 | 6.5 -10.9072 41 | 7 -10.786 42 | 7.5 -10.6546 43 | 8 -10.4564 44 | 8.5 -10.2391 45 | 9 -9.9809 46 | 9.5 -9.6747 47 | 10 -9.3111 48 | 10.5 -8.8504 49 | 11 -8.3366 50 | 11.5 -7.6529 51 | 12 -6.7107 52 | 12.5 -5.3664 53 | 13 -2.7377 54 | -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/profile2.txt: -------------------------------------------------------------------------------- 1 | -11.5 -0.1014 2 | -11 -0.9674 3 | -10.5 -1.8335 4 | -10 -2.6995 5 | -9.5 -3.5655 6 | -9 -4.4315 7 | -8.5 -5.2878 8 | -8 -6.02 9 | -7.5 -6.6344 10 | -7 -7.1614 11 | -6.5 -7.6193 12 | -6 -8.02 13 | -5.5 -8.3716 14 | -5 -8.6803 15 | -4.5 -8.9503 16 | -4 -9.1852 17 | -3.5 -9.3875 18 | -3 -9.5594 19 | -2.5 -9.7025 20 | -2 -9.818 21 | -1.5 -9.9069 22 | -1 -9.9699 23 | -0.5 -10.0075 24 | 0 -10.02 25 | 0.5 -10.0075 26 | 1 -9.9699 27 | 1.5 -9.9069 28 | 2 -9.818 29 | 2.5 -9.7025 30 | 3 -9.5594 31 | 3.5 -9.3875 32 | 4 -9.1852 33 | 4.5 -8.9503 34 | 5 -8.6803 35 | 5.5 -8.3716 36 | 6 -8.02 37 | 6.5 -7.6193 38 | 7 -7.1614 39 | 7.5 -6.6344 40 | 8 -6.02 41 | 8.5 -5.2878 42 | 9 -4.4315 43 | 9.5 -3.5655 44 | 10 -2.6995 45 | 10.5 -1.8335 46 | 11 -0.9674 47 | 11.5 -0.1014 -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/qt3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/qt3.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/save_load.hkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/save_load.hkl -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/save_load.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/save_load.npz -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/star_hole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/star_hole.png -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_XZ 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_xz.ipynb 10 | masks_xz.ipynb 11 | masks_xz_procedures.ipynb 12 | drawing_xz.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/video_xz_int_long.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/video_xz_int_long.avi -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/video_xz_int_trans.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/video_xz_int_trans.avi -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_XZ/video_xz_pha_trans.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_scalar/scalar_XZ/video_xz_pha_trans.avi -------------------------------------------------------------------------------- /docs/source/tutorial_scalar/scalar_Z/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_Z 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | 10 | scalar_field_z.ipynb 11 | -------------------------------------------------------------------------------- /docs/source/tutorial_vector/algorithms/tutorial.rst: -------------------------------------------------------------------------------- 1 | Algorithms 2 | ============= 3 | 4 | The algorithms implemented for vector propagation are: 5 | 6 | * Vector Fast Fourier Tranform (VFFT). 7 | * Vector Rayleigh-Sommerfeld (VRS). 8 | * Vector Chirped z-transform (VCZT). 9 | * Fast Polarized Wave Propagation Method (FPWPM). 10 | 11 | **Vector Fast Fourier Transform (VFFT)** 12 | 13 | - todo 14 | 15 | 16 | **Vector Rayleigh-Sommerfeld (VRS)** 17 | 18 | - H. Ye, C. W. Qiu, K. Huang, J.Teng, B. Luk’Yanchuk, S.P. Yeo,(2013). Creation of a longitudinally polarized subwavelength hotspot with an ultra-thin planar lens: Vectorial Rayleigh-Sommerfeld method. Laser Physics Letters, 10(6). https://doi.org/10.1088/1612-2011/10/6/065004 19 | 20 | The VRS method propagates (Ex,Ey,Ez) fields offering the advantage of significant reduction in computation, from flat diffractive elements (Thin Element Approximation) with full control of polarization. It addresses simultaneously both longitudinal polarization. This approach offers the advantage of significant reduction in computation. 21 | 22 | 23 | **Vector Chirped Z Transform (VCZT)** 24 | 25 | - Y. Hu, Z. Wang, X.Wang, S. Ji, C.Zhang, J. Li, W. Zhu, D.Wu, J. Chu (2020). Efficient full-path optical calculation of scalar and vector diffraction using the Bluestein method. Light: Science and Applications, 9(1). https://doi.org/10.1038/s41377-020-00362-z 26 | 27 | 28 | **Fast Polarized Wave Propagation Method (FPWPM)** 29 | 30 | * M.Wende, J. Drozella, A. Toulouse, A.M. Herkommer (2022). Fast algorithm for the simulation of 3D-printed microoptics based on the vector wave propagation method," Opt. Express 30(22), 40161-40173 https://doi.org/10.1364/OE.469178 31 | 32 | It is an efficient method for vector wave optical simulations of microoptics. The FPWPM is capable of handling comparably large simulation volumes while maintaining quick runtime. By considering polarization in simulations, the FPWPM facilitates the analysis of optical elements which employ this property of electromagnetic waves as a feature in their optical design, e.g., diffractive elements, gratings, or optics with high angle of incidence like high numerical aperture lenses. 33 | 34 | 35 | .. toctree:: 36 | :maxdepth: 2 37 | :numbered: 38 | :glob: 39 | 40 | 41 | VFFT.ipynb 42 | VRS.ipynb 43 | VCZT.ipynb 44 | FPWPM.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_vector/drawing/tutorial.rst: -------------------------------------------------------------------------------- 1 | Some info about drawing for vector fields 2 | =============================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/source/tutorial_vector/vector_XY/calibration_slm_jones_2500.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/source/tutorial_vector/vector_XY/calibration_slm_jones_2500.npz -------------------------------------------------------------------------------- /docs/source/tutorial_vector/vector_XY/tutorial.rst: -------------------------------------------------------------------------------- 1 | Vector_XY 2 | ========================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_vector_XY.ipynb 10 | tutorial_vector_sources_XY.ipynb 11 | tutorial_vector_masks_XY.ipynb 12 | tutorial_vector_XY_draw.ipynb 13 | -------------------------------------------------------------------------------- /docs/source/tutorial_vector/vector_XYZ/tutorial.rst: -------------------------------------------------------------------------------- 1 | Vector_XYZ 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_vector_XYZ.ipynb -------------------------------------------------------------------------------- /docs/source/tutorial_vector/vector_XZ/tutorial.rst: -------------------------------------------------------------------------------- 1 | Scalar_XZ 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | tutorial_vector_XZ.ipynb 10 | -------------------------------------------------------------------------------- /docs/statistics.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../STATISTICS.rst 2 | -------------------------------------------------------------------------------- /docs/todo.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../TODO.rst 2 | -------------------------------------------------------------------------------- /docs/tutorials_scalar.rst: -------------------------------------------------------------------------------- 1 | Tutorials for scalar propagation 2 | ======================================= 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | :numbered: 8 | :glob: 9 | 10 | 11 | source/tutorial_scalar/algorithms/tutorial.rst 12 | source/tutorial_scalar/comparison/tutorial.rst 13 | source/tutorial_scalar/scalar_X/tutorial.rst 14 | source/tutorial_scalar/scalar_XY/tutorial.rst 15 | source/tutorial_scalar/scalar_XYZ/tutorial.rst 16 | source/tutorial_scalar/scalar_XZ/tutorial.rst 17 | source/tutorial_scalar/scalar_Z/tutorial.rst 18 | source/tutorial_scalar/drawing/tutorial.rst 19 | source/tutorial_scalar/other/tutorial.rst 20 | 21 | -------------------------------------------------------------------------------- /docs/tutorials_vector.rst: -------------------------------------------------------------------------------- 1 | Tutorials for vector propagation 2 | ======================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :numbered: 7 | :glob: 8 | 9 | source/tutorial_vector/algorithms/tutorial.rst 10 | source/tutorial_vector/vector_XY/tutorial.rst 11 | source/tutorial_vector/vector_XZ/tutorial.rst 12 | source/tutorial_vector/vector_XYZ/tutorial.rst 13 | source/tutorial_vector/drawing/tutorial.rst 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | To use Python diffraction and interference in a project: 6 | 7 | .. code-block:: python 8 | 9 | import diffractio 10 | 11 | 12 | New procedure: Diffractio class 13 | ================================== 14 | 15 | .. code-block:: python 16 | 17 | from diffractio import np 18 | from diffractio import um, degrees 19 | from diffractio.diffractio import Diffractio 20 | 21 | x = np.linspace(-100 * um, 100 * um, 512) 22 | y = np.linspace(-100 * um, 100 * um, 512) 23 | wavelength = 0.6328 * um 24 | 25 | u0 = Diffractio("scalar", "source", x=x, y=y, z=None, wavelength=wavelength, info='source') 26 | u0.plane_wave() 27 | 28 | t = Diffractio("scalar", "mask", x=x, y=y, z=None, wavelength=wavelength, info='mask') 29 | t.square(r0=(0,0), size=100*um, angle=0*degrees) 30 | 31 | u1 = u0 * t 32 | 33 | 34 | 35 | 36 | X fields 37 | ================= 38 | 39 | .. code-block:: python 40 | 41 | from diffractio import um, nm, mm, np 42 | from diffractio.scalar_fields_X import Scalar_field_X 43 | from diffractio.scalar_sources_X import Scalar_source_X 44 | from diffractio.scalar_masks_X import Scalar_mask_X 45 | 46 | x = np.linspace(-500*um, 500*um, 4096) 47 | wavelength = .6328*um 48 | 49 | u0 = Scalar_source_X(x, wavelength) 50 | u0.gauss_beam(x0=0, w0=300*um, z0=0) 51 | u0.draw(filename='usage1.png') 52 | 53 | t0=Scalar_mask_X(x, wavelength) 54 | t0.slit(x0=0, size=250*um) 55 | t0.draw(filename='usage2.png') 56 | 57 | u1=t0*u0 58 | u2 = u1.RS(z=5*mm, new_field=True) 59 | u2.draw(filename='usage3.png') 60 | 61 | 62 | .. figure:: usage1.png 63 | :width: 600 64 | .. figure:: usage2.png 65 | :width: 600 66 | .. figure:: usage3.png 67 | :width: 600 68 | 69 | 70 | 71 | 72 | XZ fields 73 | ================= 74 | 75 | .. code-block:: python 76 | 77 | from diffractio import um, nm, mm, np,degrees 78 | from diffractio.scalar_sources_X import Scalar_source_X 79 | from diffractio.scalar_fields_XZ import Scalar_field_XZ 80 | from diffractio.scalar_masks_XZ import Scalar_mask_XZ 81 | 82 | x0 = np.linspace(-100*um, 100*um, 512) 83 | z0 = np.linspace(0*um, 300*um, 512) 84 | wavelength = 5*um 85 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 86 | u0.gauss_beam(A=1, x0=0*um, z0=0*um, w0=75*um, theta=0*degrees) 87 | u0.draw(kind='field', filename='usage4.png') 88 | 89 | u1 = Scalar_mask_XZ(x=x0, z=z0, wavelength=wavelength) 90 | u1.incident_field(u0) 91 | u1.square(r0=(0*um, 100*um), 92 | size=(100*um, 100*um), 93 | angle=45*degrees, 94 | refractive_index=2) 95 | 96 | u1.draw_refractive_index(filename='usage5.png', scale='scaled') 97 | u1.WPM(verbose=False) 98 | u1.draw(logarithm=True, normalize='maximum', draw_borders=True, filename='usage6.png', scale='scaled'); 99 | 100 | .. figure:: usage4.png 101 | :width: 600 102 | .. figure:: usage5.png 103 | :width: 600 104 | .. figure:: usage6.png 105 | :width: 600 106 | 107 | XY fields 108 | ================= 109 | 110 | .. code-block:: python 111 | 112 | from diffractio import um, nm, mm, np, degrees 113 | from diffractio.scalar_sources_XY import Scalar_source_XY 114 | from diffractio.scalar_fields_XY import Scalar_field_XY 115 | from diffractio.scalar_masks_XY import Scalar_mask_XY 116 | 117 | 118 | length = 1000*um 119 | x0 = np.linspace(-length/2, length/2, 512) 120 | y0 = np.linspace(-length/2, length/2, 512) 121 | wavelength = 0.6238*um 122 | 123 | focus=10*mm 124 | 125 | 126 | u0 = Scalar_source_XY(x=x0, y=y0, wavelength=wavelength) 127 | 128 | u0.zernike_beam(A=1, r0=(0*um, 0*um), radius=length/2, n=[ 0,4,], m=[0,3,], c_nm=[ 1,0.25,]) 129 | u0.draw(kind='phase', filename='usage7.png') 130 | 131 | t0 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 132 | t0.fresnel_lens( 133 | r0=(0*um, 0*um), 134 | radius=(500*um, 500*um), 135 | focal=(focus,focus), 136 | angle=0*degrees, 137 | kind='amplitude', 138 | phase=np.pi) 139 | t0.draw(filename='usage8.png') 140 | 141 | u1 = u0 * t0 142 | u2 = u1.RS(z=focus, new_field=True) 143 | u2.cut_resample( 144 | x_limits=(-100*um, 100*um), 145 | y_limits=(-100*um, 100*um), 146 | num_points=[1024, 1024], 147 | new_field=False) 148 | u2.draw(kind='intensity', logarithm=True, filename='usage9.png') 149 | 150 | 151 | .. figure:: usage7.png 152 | :width: 600 153 | .. figure:: usage8.png 154 | :width: 600 155 | .. figure:: usage9.png 156 | :width: 600 157 | 158 | XYZ fields 159 | ================= 160 | 161 | .. code-block:: python 162 | 163 | from diffractio import degrees, eps, mm, no_date, np, um 164 | from diffractio.scalar_fields_XYZ import Scalar_field_XYZ 165 | from diffractio.scalar_masks_XY import Scalar_mask_XY 166 | from diffractio.scalar_masks_XYZ import Scalar_mask_XYZ 167 | from diffractio.scalar_sources_XY import Scalar_source_XY 168 | 169 | x0 = np.linspace(-25*um, 25*um, 128) 170 | y0 = np.linspace(-25*um, 25*um, 128) 171 | z0 = np.linspace(100*um, 500*um, 256) 172 | wavelength = .6328*um 173 | 174 | t1 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 175 | t1.circle( 176 | r0=(0*um, 0*um), radius=(10*um, 10*um), angle=0*degrees) 177 | t1.draw(filename='usage10.png') 178 | 179 | uxyz = Scalar_mask_XYZ(x=x0, y=y0, z=z0, wavelength=wavelength) 180 | uxyz.incident_field(u0=t1) 181 | 182 | uxyz.RS(verbose=True, num_processors=1) 183 | 184 | uxyz.draw_XYZ(y0=0*mm, logarithm=True, normalize='maximum',filename='xyz_RS.png') 185 | 186 | 187 | .. figure:: usage10.png 188 | :width: 600 189 | 190 | .. figure:: xyz_RS.png 191 | :width: 600 192 | 193 | 194 | XY Vector fields 195 | ================================== 196 | 197 | .. code-block:: python 198 | 199 | from diffractio import np, sp, plt 200 | from diffractio import nm, um, mm, degrees 201 | 202 | from diffractio.scalar_sources_XY import Scalar_source_XY 203 | from diffractio.scalar_masks_XY import Scalar_mask_XY 204 | from diffractio.scalar_fields_XY import Scalar_field_XY 205 | 206 | from diffractio.vector_sources_XY import Vector_source_XY 207 | from diffractio.vector_masks_XY import Vector_mask_XY 208 | from diffractio.vector_fields_XY import Vector_field_XY 209 | 210 | x0 = np.linspace(-125*um, 125*um, 256) 211 | y0 = np.linspace(-125*um, 125*um, 256) 212 | 213 | wavelength = 0.6328*um 214 | 215 | u0 = Scalar_source_XY(x0, y0, wavelength) 216 | u0.gauss_beam(r0=(0*um, 0*um), w0=(100*um, 100*um), z0=0*um, 217 | A=1, theta=0*degrees, phi=0*degrees) 218 | 219 | EM0 = Vector_source_XY(x0, y0, wavelength) 220 | EM0.azimuthal_wave(u=u0, r0=(0*um, 0*um), radius=(200, 200)) 221 | EM0.draw(kind='ellipses') 222 | plt.title('Before mask') 223 | plt.savefig('usage12.png') 224 | 225 | 226 | t0 = Scalar_mask_XY(x0, y0, wavelength) 227 | t0.two_levels(level1=0, level2=1, x_edge=0, angle=0) 228 | 229 | M0 = Vector_mask_XY(x=x0, y=y0, wavelength=wavelength) 230 | 231 | pol_state_0 = np.array([[1, 0],[0, 0]]) 232 | pol_state_1 = np.array([[0, 0],[0, 1]]) 233 | 234 | M0.complementary_masks(t0, pol_state_0, pol_state_1) 235 | 236 | EM1 = EM0 * M0 237 | EM1.draw(kind='ellipses') 238 | plt.title('After mask') 239 | plt.savefig('usage13.png') 240 | 241 | EM2 = EM1.RS(z=10*mm) 242 | 243 | 244 | EM2.draw(kind='ellipses') 245 | plt.title('After propagation') 246 | plt.savefig('usage14.png') 247 | 248 | .. figure:: usage12.png 249 | :width: 600 250 | .. figure:: usage13.png 251 | :width: 600 252 | .. figure:: usage14.png 253 | :width: 600 254 | 255 | 256 | 257 | XZ Vector fields 258 | ================================== 259 | 260 | .. code-block:: python 261 | 262 | from diffractio import np 263 | from diffractio import degrees, um 264 | 265 | 266 | from diffractio.scalar_sources_X import Scalar_source_X 267 | from diffractio.vector_fields_XZ import Vector_field_XZ 268 | 269 | from py_pol.jones_vector import Jones_vector 270 | 271 | x0 = np.linspace(-10*um, 10*um, 1024) 272 | z0 = np.linspace(0*um, 30*um, 512) 273 | wavelength = 2*um 274 | 275 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 276 | u0.gauss_beam(A=1, x0=0, w0=2*um, z0=15*um, theta=0) 277 | 278 | j0 = Jones_vector().general_azimuth_ellipticity(azimuth=0*degrees, ellipticity=0*degrees) 279 | 280 | EH_xz = Vector_field_XZ(x0,z0, wavelength) 281 | EH_xz.incident_field(u0=u0, j0=j0) 282 | 283 | EH_xz.FP_WPM(has_edges=False) 284 | 285 | EH_xz.draw('EH', draw_z = True, draw_borders=True, scale='scaled') 286 | 287 | Sx, Sy, Sz = EH_xz.Poynting_vector_averaged(has_draw=True, draw_borders=True, scale='scaled') 288 | 289 | .. figure:: usage12.png 290 | :width: 600 291 | .. figure:: usage13.png 292 | :width: 600 293 | .. figure:: usage14.png 294 | :width: 600 -------------------------------------------------------------------------------- /docs/usage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage1.png -------------------------------------------------------------------------------- /docs/usage10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage10.png -------------------------------------------------------------------------------- /docs/usage11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage11.png -------------------------------------------------------------------------------- /docs/usage12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage12.png -------------------------------------------------------------------------------- /docs/usage13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage13.png -------------------------------------------------------------------------------- /docs/usage14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage14.png -------------------------------------------------------------------------------- /docs/usage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage2.png -------------------------------------------------------------------------------- /docs/usage3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage3.png -------------------------------------------------------------------------------- /docs/usage4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage4.png -------------------------------------------------------------------------------- /docs/usage5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage5.png -------------------------------------------------------------------------------- /docs/usage6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage6.png -------------------------------------------------------------------------------- /docs/usage7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage7.png -------------------------------------------------------------------------------- /docs/usage8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage8.png -------------------------------------------------------------------------------- /docs/usage9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/usage9.png -------------------------------------------------------------------------------- /docs/video_RS_int.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/video_RS_int.mp4 -------------------------------------------------------------------------------- /docs/xyz_RS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/docs/xyz_RS.png -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/logo.png -------------------------------------------------------------------------------- /logoUCM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/logoUCM.png -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | filterwarnings = 3 | ignore::PendingDeprecationWarning 4 | ignore::DeprecationWarning 5 | -------------------------------------------------------------------------------- /readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/conf.py 11 | 12 | build: 13 | os: ubuntu-22.04 14 | tools: 15 | python: "3.10" 16 | 17 | 18 | # Optionally build your docs in additional formats such as PDF 19 | formats: 20 | - pdf 21 | 22 | # Optionally set the version of Python and requirements required to build your docs 23 | python: 24 | version: "3.10" 25 | install: 26 | - requirements: docs/requirements.txt 27 | system_packages: true 28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | traitlets 2 | nodejs 3 | numpy>=1.20,<2 4 | scipy 5 | matplotlib 6 | py_pol 7 | screeninfo 8 | Pillow 9 | numexpr 10 | pandas 11 | ipywidgets 12 | ipympl>=0.9.3 13 | ezdxf 14 | pyvista 15 | # opencv-python 16 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | bumpversion 2 | flake8 3 | tox 4 | coverage 5 | Sphinx 6 | twine 7 | pytest-cov 8 | pytest 9 | 10 | # bumpversion==0.5.3 11 | # flake8==3.5.0 12 | # tox==3.5.2 13 | # coverage==4.5.1 14 | # Sphinx==1.8.1 15 | # twine==1.12.1 16 | 17 | # pytest-cov 18 | # pytest==7.2.1 19 | # pytest-runner==4.2 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.1.8 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | search = version='{current_version}' 8 | replace = version='{new_version}' 9 | 10 | [bumpversion:file:diffractio/__init__.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | [bdist_wheel] 15 | universal = 1 16 | 17 | [flake8] 18 | exclude = docs 19 | 20 | [aliases] 21 | # Define setup.py command aliases here 22 | test = pytest 23 | 24 | [tool:pytest] 25 | collect_ignore = ['setup.py'] 26 | 27 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """The setup script.""" 4 | 5 | from setuptools import find_packages, setup 6 | 7 | with open('README.rst', encoding='utf8') as readme_file: 8 | readme = readme_file.read() 9 | 10 | with open('HISTORY.rst', encoding='utf8') as history_file: 11 | history = history_file.read() 12 | 13 | 14 | requirements = [ 15 | 'matplotlib', 'numpy>=1.20,<2', 'scipy', 'ezdxf', 16 | 'screeninfo', 'Pillow', 'numexpr', 'pandas', 'py_pol', 17 | 'ipywidgets', 'ipympl>=0.9.3', 'opencv-python', 'psutil', 'pyvista' 18 | ] 19 | 20 | setup_requirements = [ 21 | 'pytest-runner', 22 | ] 23 | 24 | test_requirements = [ 25 | 'pytest', 26 | ] 27 | 28 | setup( 29 | author="Luis Miguel Sanchez Brea", 30 | author_email='optbrea@ucm.es', 31 | classifiers=[ 32 | 'Development Status :: 4 - Beta', 33 | 'Intended Audience :: Science/Research', 34 | 'License :: OSI Approved :: GPLv3 License', 35 | 'Natural Language :: English', 36 | 'Programming Language :: Python :: 3', 37 | 'Programming Language :: Python :: 3.8', 38 | 'Programming Language :: Python :: 3.9', 39 | 'Programming Language :: Python :: 3.10', 40 | ], 41 | description="Optical Diffraction and Interference (scalar and vectorial)", 42 | entry_points={ 43 | 'console_scripts': [ 44 | 'diffractio=diffractio.cli:main', 45 | ], 46 | }, 47 | install_requires=requirements, 48 | license="GPLv3 license", 49 | # long_description=readme + '\n\n' + history, 50 | long_description=readme, 51 | include_package_data=True, 52 | keywords=[ 53 | 'diffractio', 'optics', 'diffraction', 'interference', 54 | 'BPM', 'WPM', 'CZT', 'RS', 'VRS', 'VCZT', 'FPWPM' 55 | ], 56 | name='diffractio', 57 | packages=find_packages(include=['diffractio']), 58 | setup_requires=setup_requirements, 59 | test_suite='tests', 60 | tests_require=test_requirements, 61 | url='https://github.com/optbrea/diffractio', 62 | version='0.3.1', 63 | zip_safe=False, 64 | ) -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/tests/__init__.py -------------------------------------------------------------------------------- /tests/profile1.txt: -------------------------------------------------------------------------------- 1 | -13 -2.7377 2 | -12.5 -5.3664 3 | -12 -6.7107 4 | -11.5 -7.6529 5 | -11 -8.3366 6 | -10.5 -8.8504 7 | -10 -9.3111 8 | -9.5 -9.6747 9 | -9 -9.9809 10 | -8.5 -10.2391 11 | -8 -10.4564 12 | -7.5 -10.6546 13 | -7 -10.786 14 | -6.5 -10.9072 15 | -6 -11.0022 16 | -5.5 -11.0741 17 | -5 -11.1238 18 | -4.5 -11.1711 19 | -4 -11.1711 20 | -3.5 -11.172 21 | -3 -11.1594 22 | -2.5 -11.1366 23 | -2 -11.1043 24 | -1.5 -11.0755 25 | -1 -11.0454 26 | -0.5 -11.0269 27 | 0 -11.02 28 | 0.5 -11.0269 29 | 1 -11.0454 30 | 1.5 -11.0755 31 | 2 -11.1043 32 | 2.5 -11.1366 33 | 3 -11.1594 34 | 3.5 -11.172 35 | 4 -11.1711 36 | 4.5 -11.1711 37 | 5 -11.1238 38 | 5.5 -11.0741 39 | 6 -11.0022 40 | 6.5 -10.9072 41 | 7 -10.786 42 | 7.5 -10.6546 43 | 8 -10.4564 44 | 8.5 -10.2391 45 | 9 -9.9809 46 | 9.5 -9.6747 47 | 10 -9.3111 48 | 10.5 -8.8504 49 | 11 -8.3366 50 | 11.5 -7.6529 51 | 12 -6.7107 52 | 12.5 -5.3664 53 | 13 -2.7377 54 | -------------------------------------------------------------------------------- /tests/profile2.txt: -------------------------------------------------------------------------------- 1 | -11.5 -0.1014 2 | -11 -0.9674 3 | -10.5 -1.8335 4 | -10 -2.6995 5 | -9.5 -3.5655 6 | -9 -4.4315 7 | -8.5 -5.2878 8 | -8 -6.02 9 | -7.5 -6.6344 10 | -7 -7.1614 11 | -6.5 -7.6193 12 | -6 -8.02 13 | -5.5 -8.3716 14 | -5 -8.6803 15 | -4.5 -8.9503 16 | -4 -9.1852 17 | -3.5 -9.3875 18 | -3 -9.5594 19 | -2.5 -9.7025 20 | -2 -9.818 21 | -1.5 -9.9069 22 | -1 -9.9699 23 | -0.5 -10.0075 24 | 0 -10.02 25 | 0.5 -10.0075 26 | 1 -9.9699 27 | 1.5 -9.9069 28 | 2 -9.818 29 | 2.5 -9.7025 30 | 3 -9.5594 31 | 3.5 -9.3875 32 | 4 -9.1852 33 | 4.5 -8.9503 34 | 5 -8.6803 35 | 5.5 -8.3716 36 | 6 -8.02 37 | 6.5 -7.6193 38 | 7 -7.1614 39 | 7.5 -6.6344 40 | 8 -6.02 41 | 8.5 -5.2878 42 | 9 -4.4315 43 | 9.5 -3.5655 44 | 10 -2.6995 45 | 10.5 -1.8335 46 | 11 -0.9674 47 | 11.5 -0.1014 -------------------------------------------------------------------------------- /tests/spain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/tests/spain.png -------------------------------------------------------------------------------- /tests/star_hole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/tests/star_hole.png -------------------------------------------------------------------------------- /tests/test_scalar_masks_XYZ.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | """ 4 | Test for scalar_sources_XYZ""" 5 | 6 | import datetime 7 | import os 8 | import sys 9 | 10 | from diffractio import degrees, no_date, np, um 11 | from diffractio.scalar_masks_XY import Scalar_mask_XY 12 | from diffractio.scalar_masks_XYZ import Scalar_mask_XYZ 13 | from diffractio.utils_tests import comparison, save_figure_test 14 | 15 | if no_date is True: 16 | date = '0' 17 | else: 18 | now = datetime.datetime.now() 19 | date = now.strftime("%Y-%m-%d_%H") 20 | 21 | path_base = "tests_results" 22 | path_class = "scalar_masks_XYZ" 23 | 24 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 25 | 26 | if not os.path.exists(newpath): 27 | os.makedirs(newpath) 28 | 29 | 30 | class Test_Scalar_masks_XYZ(): 31 | 32 | def test_sphere(self): 33 | func_name = sys._getframe().f_code.co_name 34 | # filename = '{}{}'.format(newpath, func_name) 35 | 36 | length = 100*um 37 | numdataX = 64 38 | numdataZ = 64 39 | 40 | longitud = 50*um 41 | 42 | x0 = np.linspace(-length/2, length/2, numdataX) 43 | y0 = np.linspace(-length/2, length/2, numdataX) 44 | z0 = np.linspace(-longitud, longitud, numdataZ) 45 | wavelength = 0.55*um 46 | 47 | t1 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 48 | t1.circle(r0=(0*um, 0*um), 49 | radius=(20*um, 20*um), 50 | angle=0*degrees) 51 | 52 | uxyz = Scalar_mask_XYZ(x=x0, 53 | y=y0, 54 | z=z0, 55 | wavelength=wavelength, 56 | n_background=1., 57 | info='') 58 | uxyz.sphere(r0=(0*um, 0*um, 0*um), 59 | radius=(10*um, 30*um, 50*um), 60 | refractive_index=2, 61 | angles=(0*degrees, 0*degrees, 45*degrees)) 62 | uxyz.incident_field(t1) 63 | assert True 64 | -------------------------------------------------------------------------------- /tests/test_scalar_sources_X.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | 4 | # ------------------------------------------------------------------------------- 5 | # Name: scalar_sources_X.py 6 | # Purpose: 1D light sources tests 7 | # 8 | # Author: Luis Miguel Sanchez Brea 9 | # 10 | # Created: 2019/01/30 11 | # 12 | # Licence: GPLv3 13 | # ------------------------------------------------------------------------------- 14 | 15 | import datetime 16 | import os 17 | import sys 18 | 19 | from diffractio import degrees, mm, no_date, np, um 20 | from diffractio.scalar_sources_X import Scalar_source_X 21 | from diffractio.utils_tests import comparison, save_figure_test 22 | 23 | # from functools import wraps 24 | 25 | if no_date is True: 26 | date = '0' 27 | else: 28 | now = datetime.datetime.now() 29 | date = now.strftime("%Y-%m-%d_%H") 30 | 31 | path_base = "tests_results" 32 | path_class = "scalar_sources_X" 33 | 34 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 35 | 36 | if not os.path.exists(newpath): 37 | os.makedirs(newpath) 38 | 39 | 40 | class Test_Scalar_sources_X(): 41 | # def saving_data(f): 42 | # @wraps(f) 43 | # def wrapped(inst, *args, **kwargs): 44 | # func_name = sys._getframe().f_code.co_name 45 | # filename = '{}{}'.format(newpath, func_name) 46 | # print(filename) 47 | # 48 | # u0 = f(inst, *args, **kwargs) 49 | # u0.save_data(filename=filename+'.npz') 50 | # save_figure_test(newpath, func_name) 51 | # assert True 52 | # 53 | # assert True 54 | # #return wrapped 55 | 56 | def test_plane_wave(self): 57 | func_name = sys._getframe().f_code.co_name 58 | filename = '{}{}'.format(newpath, func_name) 59 | 60 | x0 = np.linspace(-1000*um, 1000*um, 512) 61 | wavelength = 0.6328*um 62 | 63 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 64 | u0.plane_wave(theta=1*degrees, z0=0*um) 65 | u0.draw(kind='field') 66 | 67 | u0.save_data(filename=filename + '.npz') 68 | save_figure_test(newpath, func_name) 69 | assert True 70 | 71 | def test_gauss_beam(self): 72 | func_name = sys._getframe().f_code.co_name 73 | filename = '{}{}'.format(newpath, func_name) 74 | 75 | x0 = np.linspace(-500*um, 500*um, 2048) 76 | wavelength = .5*um 77 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 78 | u0.gauss_beam(A=1, 79 | x0=0*um, 80 | z0=-2000*um, 81 | w0=25*um, 82 | theta=0*degrees) 83 | 84 | u0.draw(kind='field') 85 | 86 | u0.save_data(filename=filename + '.npz') 87 | save_figure_test(newpath, func_name) 88 | assert True 89 | 90 | def test_spherical_wave_convergent(self): 91 | func_name = sys._getframe().f_code.co_name 92 | filename = '{}{}'.format(newpath, func_name) 93 | 94 | x0 = np.linspace(-500*um, 500*um, 1024) 95 | wavelength = 0.6328*um 96 | 97 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 98 | u0.spherical_wave(A=1, x0=0*um, z0=5*mm) 99 | u0.pupil(x0=0, radius=200*um) 100 | u0.draw(kind='field') 101 | 102 | u0.save_data(filename=filename + '.npz') 103 | save_figure_test(newpath, func_name) 104 | assert True 105 | 106 | def test_spherical_wave_divergent(self): 107 | func_name = sys._getframe().f_code.co_name 108 | filename = '{}{}'.format(newpath, func_name) 109 | 110 | x0 = np.linspace(-500*um, 500*um, 1024) 111 | wavelength = 0.6328*um 112 | 113 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 114 | u0.spherical_wave(A=1, x0=0*um, z0=-5*mm) 115 | u0.pupil(x0=0, radius=200*um) 116 | u0.draw(kind='field') 117 | 118 | u0.save_data(filename=filename + '.npz') 119 | save_figure_test(newpath, func_name) 120 | assert True 121 | 122 | def test_plane_waves_several_inclined(self): 123 | func_name = sys._getframe().f_code.co_name 124 | filename = '{}{}'.format(newpath, func_name) 125 | 126 | x0 = np.linspace(-500*um, 500*um, 1024) 127 | wavelength = 0.6328*um 128 | 129 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 130 | u0.plane_waves_several_inclined(A=1, 131 | num_beams=5, 132 | max_angle=5*degrees) 133 | u0.draw(kind='field') 134 | 135 | u0.save_data(filename=filename + '.npz') 136 | save_figure_test(newpath, func_name) 137 | assert True 138 | 139 | def test_plane_waves_dict(self): 140 | assert True 141 | 142 | def test_gauss_beams_several_parallel(self): 143 | func_name = sys._getframe().f_code.co_name 144 | filename = '{}{}'.format(newpath, func_name) 145 | 146 | x0 = np.linspace(-500*um, 500*um, 1024) 147 | wavelength = 0.6328*um 148 | 149 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 150 | u0.gauss_beams_several_parallel(A=1, 151 | num_beams=5, 152 | w0=50*um, 153 | z0=0*um, 154 | x_central=0*um, 155 | x_range=750*um, 156 | theta=0*degrees) 157 | u0.draw(kind='field') 158 | 159 | u0.save_data(filename=filename + '.npz') 160 | save_figure_test(newpath, func_name) 161 | assert True 162 | 163 | def test_gauss_beams_several_inclined(self): 164 | func_name = sys._getframe().f_code.co_name 165 | filename = '{}{}'.format(newpath, func_name) 166 | 167 | x0 = np.linspace(-500*um, 500*um, 1024) 168 | wavelength = 0.6328*um 169 | 170 | u0 = Scalar_source_X(x=x0, wavelength=wavelength) 171 | u0.gauss_beams_several_inclined(A=1, 172 | num_beams=5, 173 | w0=250*um, 174 | x0=0*um, 175 | z0=0*um, 176 | max_angle=5*degrees) 177 | u0.draw(kind='field') 178 | 179 | u0.save_data(filename=filename + '.npz') 180 | save_figure_test(newpath, func_name) 181 | assert True 182 | 183 | def test_interferences(self): 184 | func_name = sys._getframe().f_code.co_name 185 | filename = '{}{}'.format(newpath, func_name) 186 | 187 | length = 2*mm 188 | x0 = np.linspace(-length/2, length/2, 1024) 189 | wavelength0 = 0.6238*um 190 | 191 | u1 = Scalar_source_X(x=x0, wavelength=wavelength0) 192 | u2 = Scalar_source_X(x=x0, wavelength=wavelength0) 193 | 194 | u1.gauss_beam(A=1, 195 | x0=0*um, 196 | z0=0*um, 197 | w0=250*um, 198 | theta=.25*degrees) 199 | u2.gauss_beam(A=1, 200 | x0=0*um, 201 | z0=0*um, 202 | w0=250*um, 203 | theta=-.25*degrees) 204 | 205 | u0 = u1 + u2 206 | u0.draw(kind='intensity') 207 | 208 | u0.save_data(filename=filename + '.npz') 209 | save_figure_test(newpath, func_name) 210 | assert True 211 | -------------------------------------------------------------------------------- /tests/test_utils_math.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | 4 | # ------------------------------------------------------------------------------- 5 | # Name: scalar_fields_XZ.py 6 | # Purpose: tests 7 | # 8 | # Author: Luis Miguel Sanchez Brea 9 | # 10 | # Created: 2017 11 | # Copyright: 12 | # Licence: GPL 13 | # ------------------------------------------------------------------------------- 14 | import datetime 15 | import os 16 | import sys 17 | 18 | import numpy as np 19 | from diffractio import eps, no_date 20 | from diffractio.utils_math import (amplitude2phase, binarize, distance, 21 | nearest, nearest2, normalize) 22 | from diffractio.utils_tests import comparison 23 | 24 | if no_date is True: 25 | date = '0' 26 | else: 27 | now = datetime.datetime.now() 28 | date = now.strftime("%Y-%m-%d_%H") 29 | 30 | path_base = "tests_results" 31 | path_class = "utils_math" 32 | 33 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 34 | 35 | if not os.path.exists(newpath): 36 | os.makedirs(newpath) 37 | 38 | 39 | class Test_utils_math(): 40 | def test_distance(self): 41 | func_name = sys._getframe().f_code.co_name 42 | 43 | solution = 1. 44 | x1 = np.array([0, 1, 1]) 45 | x2 = np.array([0, 0, 1]) 46 | proposal = distance(x1, x2) 47 | assert comparison(proposal, solution, eps), func_name 48 | 49 | solution = np.sqrt(3) 50 | x1 = np.array([0, 0, 0]) 51 | x2 = np.array([1, 1, 1]) 52 | proposal = distance(x1, x2) 53 | assert comparison(proposal, solution, eps), func_name 54 | 55 | solution = np.sqrt(2) 56 | x1 = np.array([0, 0, 1j]) 57 | x2 = np.array([0, 0, 1]) 58 | proposal = distance(x1, x2) 59 | assert comparison(proposal, solution, eps), func_name 60 | 61 | def test_nearest(self): 62 | func_name = sys._getframe().f_code.co_name 63 | 64 | solution = 10 65 | x = np.linspace(0, 10, 21) 66 | x0 = 5 67 | proposal, _, _ = nearest(x, x0) 68 | assert comparison(proposal, solution, eps), func_name 69 | 70 | def test_nearest2(self): 71 | func_name = sys._getframe().f_code.co_name 72 | 73 | x = np.linspace(0, 10, 11) 74 | 75 | solution = x 76 | proposal, _, _ = nearest2(x, x) 77 | assert comparison(proposal, solution, eps), func_name 78 | 79 | def test_meshgrid(self): 80 | func_name = sys._getframe().f_code.co_name 81 | 82 | solution = np.array([[0, 1], [0, 1], [0, 1]]) 83 | x, y = [0, 1], [2, 3, 4] 84 | X, Y = np.meshgrid(x, y) 85 | print(X) 86 | print(solution) 87 | proposal = X 88 | assert comparison(proposal, solution, eps), func_name 89 | 90 | def test_binarize(self): 91 | func_name = sys._getframe().f_code.co_name 92 | 93 | solution = np.array([0., 0., 0., 1., 1., 1.]) 94 | vector = np.linspace(0, 1, 6) 95 | proposal = binarize(vector, min_value=0, max_value=1) 96 | assert comparison(proposal, solution, eps), func_name 97 | 98 | solution = np.array([-1., -1., -1., 1., 1., 1.]) 99 | vector = np.linspace(-1, 1, 6) 100 | proposal = binarize(vector, min_value=-1, max_value=1) 101 | assert comparison(proposal, solution, eps), func_name 102 | 103 | def test_amplitude2phase(self): 104 | func_name = sys._getframe().f_code.co_name 105 | 106 | u = np.linspace(0, 2 * np.pi, 6) 107 | solution = np.exp(1j * u) 108 | proposal = amplitude2phase(u) 109 | assert comparison(proposal, solution, eps), func_name 110 | 111 | def test_phase2amplitude(self): 112 | # TODO:test 113 | 114 | assert True 115 | 116 | def test_normalize(self): 117 | func_name = sys._getframe().f_code.co_name 118 | 119 | solution = np.array([1, 1]) / np.sqrt(2) 120 | v = np.array([1, 1]) 121 | proposal = normalize(v, 2) 122 | assert comparison(proposal, solution, eps), func_name 123 | 124 | solution = np.array([1 + 1j, 0]) / np.sqrt(2) 125 | v = np.array([1 + 1j, 0]) 126 | proposal = normalize(v, 2) 127 | assert comparison(proposal, solution, eps), func_name 128 | 129 | def test_vector_product(self): 130 | # TODO:test 131 | 132 | assert True 133 | 134 | def test_dot_product(self): 135 | # TODO:test 136 | 137 | assert True 138 | 139 | def test_divergence(self): 140 | # TODO:test 141 | 142 | assert True 143 | 144 | def test_curl(self): 145 | # TODO:test 146 | 147 | assert True 148 | 149 | def test_get_transitions(self): 150 | # TODO:test 151 | 152 | assert True 153 | 154 | def test_cut_function(self): 155 | # TODO:test 156 | 157 | assert True 158 | 159 | def test_fft_convolution2d(self): 160 | # TODO:test 161 | 162 | assert True 163 | 164 | def test_fft_convolution1d(self): 165 | # TODO:test 166 | 167 | assert True 168 | 169 | def test_fft_correlation1d(self): 170 | # TODO:test 171 | 172 | assert True 173 | 174 | def test_fft_correlation2d(self): 175 | # TODO:test 176 | 177 | assert True 178 | 179 | def test_rotate_image(self): 180 | # TODO:test 181 | 182 | assert True 183 | -------------------------------------------------------------------------------- /tests/test_utils_multiprocessing.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | 4 | # ------------------------------------------------------------------------------- 5 | # Name: scalar_fields_XZ.py 6 | # Purpose: tests 7 | # 8 | # Author: Luis Miguel Sanchez Brea 9 | # 10 | # Created: 2017 11 | # Copyright: 12 | # Licence: GPL 13 | # ------------------------------------------------------------------------------- 14 | import datetime 15 | import os 16 | import time 17 | 18 | import numpy as np 19 | from diffractio import no_date 20 | from diffractio.utils_multiprocessing import auxiliar_multiprocessing 21 | 22 | if no_date is True: 23 | date = '0' 24 | else: 25 | now = datetime.datetime.now() 26 | date = now.strftime("%Y-%m-%d_%H") 27 | 28 | path_base = "tests_results" 29 | path_class = "utils_math" 30 | 31 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 32 | 33 | if not os.path.exists(newpath): 34 | os.makedirs(newpath) 35 | 36 | 37 | def function_to_test(iterable, constant): 38 | return iterable**2 * constant 39 | 40 | 41 | class Test_utils_math(): 42 | def test_distance(self): 43 | 44 | dict_constants = {'x': 3, 'y': 4} 45 | N = 50000 46 | variable_process = np.linspace(0, 1, N) 47 | start = time.time() 48 | sc = auxiliar_multiprocessing() 49 | sc.execute_multiprocessing(function_to_test, variable_process, 1, 8) 50 | # print("{}".format(np.array(sc.result))) 51 | print("8 processes pool took {} seconds".format(time.time() - start)) 52 | start = time.time() 53 | res = np.zeros(N) 54 | for ind, val in enumerate(variable_process): 55 | res[ind] = function_to_test(val, 1) 56 | print( 57 | "Single process pool took {} seconds".format(time.time() - start)) 58 | 59 | assert True 60 | -------------------------------------------------------------------------------- /tests/test_vector_draw_XY.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | import datetime 4 | import os 5 | import sys 6 | 7 | from diffractio import mm, no_date, np, um 8 | from diffractio.utils_tests import save_figure_test 9 | from diffractio.vector_sources_XY import Vector_source_XY 10 | 11 | path_base = "tests_results" 12 | path_class = "Vector_draw_XY" 13 | 14 | if no_date is True: 15 | date = '0' 16 | else: 17 | now = datetime.datetime.now() 18 | date = now.strftime("%Y-%m-%d_%H") 19 | 20 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 21 | 22 | if not os.path.exists(newpath): 23 | os.makedirs(newpath) 24 | 25 | v_lineal = (1, 0) 26 | v_circular = (1, 1j) / np.sqrt(2) 27 | 28 | length = 500*um 29 | num_data = 256 30 | wavelength = 0.6328*um 31 | 32 | x0 = np.linspace(-length/2, length/2, num_data) 33 | y0 = np.linspace(-length/2, length/2, num_data) 34 | 35 | EM = Vector_source_XY(x0, y0, wavelength) 36 | EM.azimuthal_wave(u=1, r0=(0*um, 0*um), radius=(length / 5, length / 5)) 37 | EM.VRS(z=30*mm, new_field=False) 38 | 39 | Ex, Ey, _ = EM.get() 40 | 41 | EM.reduce_matrix = '' 42 | 43 | 44 | class Test_Vector_fields_XY(): 45 | 46 | def test_draw_intensity(self): 47 | 48 | func_name = sys._getframe().f_code.co_name 49 | # filename = '{}{}.npz'.format(newpath, func_name) 50 | 51 | EM.draw(kind='intensity') 52 | save_figure_test(newpath, func_name, add_name='') 53 | assert True 54 | 55 | def test_draw_intensities(self): 56 | 57 | func_name = sys._getframe().f_code.co_name 58 | # filename = '{}{}.npz'.format(newpath, func_name) 59 | 60 | EM.draw(kind='intensities') 61 | save_figure_test(newpath, func_name, add_name='') 62 | assert True 63 | 64 | def test_draw_phases(self): 65 | 66 | func_name = sys._getframe().f_code.co_name 67 | # filename = '{}{}.npz'.format(newpath, func_name) 68 | 69 | EM.draw(kind='phases') 70 | save_figure_test(newpath, func_name, add_name='') 71 | assert True 72 | 73 | def test_draw_fields(self): 74 | 75 | func_name = sys._getframe().f_code.co_name 76 | # filename = '{}{}.npz'.format(newpath, func_name) 77 | 78 | EM.draw(kind='fields') 79 | save_figure_test(newpath, func_name, add_name='') 80 | assert True 81 | 82 | def test_draw_stokes(self): 83 | 84 | func_name = sys._getframe().f_code.co_name 85 | # filename = '{}{}.npz'.format(newpath, func_name) 86 | 87 | EM.draw(kind='stokes') 88 | save_figure_test(newpath, func_name, add_name='') 89 | assert True 90 | 91 | def test_draw_param_ellipse(self): 92 | 93 | func_name = sys._getframe().f_code.co_name 94 | # filename = '{}{}.npz'.format(newpath, func_name) 95 | 96 | EM.draw(kind='param_ellipse') 97 | save_figure_test(newpath, func_name, add_name='') 98 | assert True 99 | -------------------------------------------------------------------------------- /tests/test_vector_fields_XY.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | 4 | import datetime 5 | import os 6 | import sys 7 | 8 | from diffractio import degrees, mm, no_date, np, um 9 | from diffractio.scalar_masks_XY import Scalar_mask_XY 10 | from diffractio.scalar_sources_XY import Scalar_source_XY 11 | from diffractio.utils_tests import save_figure_test 12 | from diffractio.vector_masks_XY import Vector_mask_XY 13 | from diffractio.vector_sources_XY import Vector_source_XY 14 | 15 | path_base = "tests_results" 16 | path_class = "Vector_fields_XY" 17 | 18 | if no_date is True: 19 | date = '0' 20 | else: 21 | now = datetime.datetime.now() 22 | date = now.strftime("%Y-%m-%d_%H") 23 | 24 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 25 | 26 | if not os.path.exists(newpath): 27 | os.makedirs(newpath) 28 | 29 | v_lineal = (1, 0, 0) 30 | v_circular = (1, 1j, 0) / np.sqrt(2) 31 | 32 | 33 | class Test_Vector_fields_XY(): 34 | 35 | def test_save_load(self): 36 | # func_name = sys._getframe().f_code.co_name 37 | # filename = '{}{}.npz'.format(newpath, func_name) 38 | assert True 39 | 40 | def test_clear_field(self): 41 | # func_name = sys._getframe().f_code.co_name 42 | # filename = '{}{}.npz'.format(newpath, func_name) 43 | assert True 44 | 45 | def test_mul(self): 46 | func_name = sys._getframe().f_code.co_name 47 | # filename = '{}{}.npz'.format(newpath, func_name) 48 | 49 | length = 250*um 50 | num_data = 256 51 | wavelength = 0.6328*um 52 | 53 | x0 = np.linspace(-length/2, length/2, num_data) 54 | y0 = np.linspace(-length/2, length/2, num_data) 55 | 56 | mask = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 57 | mask.fresnel_lens(r0=(0*um, 0*um), 58 | radius=(125*um, 125*um), 59 | focal=(2*mm, 2*mm), 60 | kind='amplitudes') 61 | 62 | pol_state = np.array([[1, 0], [0, 1j]]) 63 | 64 | vc = Vector_mask_XY(x0, y0, wavelength) 65 | vc.scalar_to_vector_mask(mask=mask, pol_state=pol_state) 66 | 67 | vp = Vector_mask_XY(x0, y0, wavelength) 68 | vp.polarizer_linear(azimuth=0*degrees) 69 | 70 | EM = vp 71 | EM.draw(kind='intensities') 72 | save_figure_test(newpath, func_name, add_name='_vc') 73 | 74 | EM2 = vc * vp 75 | EM2.draw(kind='stokes') 76 | save_figure_test(newpath, func_name, add_name='_vp') 77 | assert True 78 | 79 | def test_generar_field_vectorial1(self): 80 | """ 81 | aquí vemos cómo se puede generar el field vectorial a partir 82 | de vueltas sucesivas a los fields E y H 83 | """ 84 | func_name = sys._getframe().f_code.co_name 85 | # filename = '{}{}.npz'.format(newpath, func_name) 86 | 87 | length = 250*um 88 | num_data = 512 89 | x0 = np.linspace(-length/2, length/2, num_data) 90 | y0 = np.linspace(-length/2, length/2, num_data) 91 | wavelength = 0.6328 92 | 93 | EM = Vector_source_XY(x0, y0, wavelength) 94 | EM.azimuthal_wave(u=1, 95 | r0=(0*um, 0*um), 96 | radius=(length / 5, length / 5)) 97 | 98 | EM.draw(kind='stokes') 99 | save_figure_test(newpath, func_name, add_name='_0') 100 | 101 | EM.draw(kind='intensities') 102 | save_figure_test(newpath, func_name, add_name='_2') 103 | 104 | assert True 105 | 106 | def test_generar_field_vectorial2(self): 107 | """ 108 | Lo mismo que antes, pero con la operación utils, sin testeo 109 | """ 110 | 111 | func_name = sys._getframe().f_code.co_name 112 | # filename = '{}{}.npz'.format(newpath, func_name) 113 | 114 | length = 250*um 115 | num_data = 256 116 | x0 = np.linspace(-length/2, length/2, num_data) 117 | y0 = np.linspace(-length/2, length/2, num_data) 118 | wavelength = 2 119 | 120 | u0 = Scalar_source_XY(x0, y0, wavelength) 121 | u0.gauss_beam(A=1, z0=0*um, r0=(0*um, 0*um), w0=(25*um, 25*um)) 122 | 123 | EM = Vector_source_XY(x0, y0, wavelength) 124 | EM.constant_polarization(u0, v=[1, 1]) 125 | 126 | EM.draw(kind='stokes') 127 | save_figure_test(newpath, func_name, add_name='_0') 128 | EM.draw(kind='intensities') 129 | save_figure_test(newpath, func_name, add_name='_1') 130 | assert True 131 | 132 | def test_plane_wave_generacion(self): 133 | func_name = sys._getframe().f_code.co_name 134 | # filename = '{}{}.npz'.format(newpath, func_name) 135 | 136 | length = 500*um 137 | num_data = 16 138 | x0 = np.linspace(-length/2, length/2, num_data) 139 | y0 = np.linspace(-length/2, length/2, num_data) 140 | wavelength = 0.6328 141 | 142 | # con esto definimos el field E 143 | EM = Vector_source_XY(x0, y0, wavelength) 144 | EM.constant_polarization(u=1, v=[1, 0]) 145 | 146 | EM.draw(kind='stokes') 147 | save_figure_test(newpath, func_name, add_name='_0') 148 | EM.draw(kind='intensities') 149 | save_figure_test(newpath, func_name, add_name='_1') 150 | 151 | t1 = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 152 | t1.circle(r0=(0*um, 0*um), 153 | radius=( 154 | length/2, 155 | length/2, 156 | ), 157 | angle=0*degrees) 158 | 159 | EM.apply_mask(t1) 160 | 161 | EM.draw(kind='stokes') 162 | save_figure_test(newpath, func_name, add_name='_2') 163 | EM.draw(kind='intensities') 164 | save_figure_test(newpath, func_name, add_name='_3') 165 | 166 | assert True 167 | 168 | def test_RS(self): 169 | func_name = sys._getframe().f_code.co_name 170 | # filename = '{}{}.npz'.format(newpath, func_name) 171 | 172 | num_data = 256 173 | length = 150*um 174 | x0 = np.linspace(-length/2, length/2, num_data) 175 | y0 = np.linspace(-length/2, length/2, num_data) 176 | wavelength = 2*um 177 | 178 | EM = Vector_source_XY(x0, y0, wavelength) 179 | EM.local_polarized_vector_wave_radial(u=1, 180 | r0=(0*um, 0*um), 181 | m=1, 182 | fi0=0, 183 | radius=0.) 184 | EM.pupil() 185 | 186 | EM.draw(kind='stokes') 187 | save_figure_test(newpath, func_name, add_name='_1EH') 188 | 189 | EM.draw(kind='intensities') 190 | save_figure_test(newpath, func_name, add_name='_2S') 191 | 192 | EMz = EM.VRS(z=.5*mm) 193 | EMz.draw(kind='intensities') 194 | save_figure_test(newpath, func_name, add_name='_3EH_p') 195 | 196 | EMz.draw(kind='intensities') 197 | save_figure_test(newpath, func_name, add_name='_4S_p') 198 | 199 | return True 200 | 201 | def test_VRS(self): 202 | func_name = sys._getframe().f_code.co_name 203 | # filename = '{}{}.npz'.format(newpath, func_name) 204 | 205 | num_data = 256 206 | length = 150*um 207 | x0 = np.linspace(-length/2, length/2, num_data) 208 | y0 = np.linspace(-length/2, length/2, num_data) 209 | wavelength = 2*um 210 | 211 | EM = Vector_source_XY(x0, y0, wavelength) 212 | EM.local_polarized_vector_wave_radial(u=1, 213 | r0=(0*um, 0*um), 214 | m=1, 215 | fi0=0, 216 | radius=0.) 217 | EM.pupil() 218 | 219 | EM.draw(kind='stokes') 220 | save_figure_test(newpath, func_name, add_name='_1EH') 221 | 222 | EM.draw(kind='intensities') 223 | save_figure_test(newpath, func_name, add_name='_2S') 224 | 225 | EMz = EM.VRS(z=.5*mm) 226 | EMz.draw(kind='intensities') 227 | save_figure_test(newpath, func_name, add_name='_3EH_p') 228 | 229 | EMz.draw(kind='intensities') 230 | save_figure_test(newpath, func_name, add_name='_4S_p') 231 | 232 | return True 233 | -------------------------------------------------------------------------------- /tests/test_vector_masks_XY.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | 3 | 4 | import datetime 5 | import os 6 | import sys 7 | 8 | from diffractio import degrees, mm, no_date, np, um 9 | from diffractio.scalar_masks_XY import Scalar_mask_XY 10 | from diffractio.utils_tests import save_figure_test 11 | from diffractio.vector_masks_XY import Vector_mask_XY 12 | from py_pol.jones_matrix import Jones_matrix 13 | 14 | path_base = "tests_results" 15 | path_class = "vector_masks_XY" 16 | 17 | if no_date is True: 18 | date = '0' 19 | else: 20 | now = datetime.datetime.now() 21 | date = now.strftime("%Y-%m-%d_%H") 22 | 23 | newpath = "{}_{}/{}/".format(path_base, date, path_class) 24 | 25 | if not os.path.exists(newpath): 26 | os.makedirs(newpath) 27 | 28 | polarization_x = [1, 0] 29 | polarization_y = [0, 1] 30 | polarization_right = [1, 1.j] / np.sqrt(2) 31 | polarization_left = [1, -1.j] / np.sqrt(2) 32 | polarization_45 = [1, 1] / np.sqrt(2) 33 | polarization_m45 = [1, -1] / np.sqrt(2) 34 | 35 | 36 | class Test_vector_masks_XY(): 37 | 38 | def test_equal_mask(self): 39 | func_name = sys._getframe().f_code.co_name 40 | # filename = '{}{}.npz'.format(newpath, func_name) 41 | length = 250*um 42 | num_data = 256 43 | wavelength = 0.6328*um 44 | 45 | x0 = np.linspace(-length/2, length/2, num_data) 46 | y0 = np.linspace(-length/2, length/2, num_data) 47 | 48 | # mask escalar 49 | mask = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 50 | mask.ring(r0=(0*um, 0*um), 51 | radius1=(25*um, 25*um), 52 | radius2=(75*um, 75*um), 53 | angle=0*degrees) 54 | 55 | # mask vectorial 56 | pol_state = np.array([[1, 0], [1, 1j]]) 57 | 58 | EM = Vector_mask_XY(x0, y0, wavelength) 59 | EM.scalar_to_vector_mask(mask=mask, pol_state=pol_state) 60 | 61 | EM.draw(kind='jones_ap') 62 | save_figure_test(newpath, func_name, add_name='') 63 | assert True 64 | 65 | def test_complementary_mask(self): 66 | func_name = sys._getframe().f_code.co_name 67 | # filename = '{}{}.npz'.format(newpath, func_name) 68 | 69 | length = 250*um 70 | num_data = 256 71 | wavelength = 0.6328*um 72 | 73 | x0 = np.linspace(-length/2, length/2, num_data) 74 | y0 = np.linspace(-length/2, length/2, num_data) 75 | 76 | mask = Scalar_mask_XY(x=x0, y=y0, wavelength=wavelength) 77 | mask.fresnel_lens(r0=(0*um, 0*um), 78 | radius=(125*um, 125*um), 79 | focal=(2*mm, 2*mm), 80 | angle=0*degrees, 81 | kind='amplitudes') 82 | 83 | EM = Vector_mask_XY(x0, y0, wavelength) 84 | EM.complementary_masks(mask=mask, 85 | pol_state_0=np.array([[1, 0], [0, 0]]), 86 | pol_state_1=np.array([[0, 0], [0, 1]])) 87 | 88 | EM.draw(kind='amplitudes') 89 | save_figure_test(newpath, func_name, add_name='_amplitude') 90 | EM.draw(kind='phase') 91 | save_figure_test(newpath, func_name, add_name='_phase') 92 | assert True 93 | 94 | def test_from_py_pol(self): 95 | func_name = sys._getframe().f_code.co_name 96 | # filename = '{}{}.npz'.format(newpath, func_name) 97 | 98 | length = 250*um 99 | num_data = 256 100 | wavelength = 0.6328*um 101 | 102 | x0 = np.linspace(-length/2, length/2, num_data) 103 | y0 = np.linspace(-length/2, length/2, num_data) 104 | 105 | PL = Jones_matrix('m0') 106 | PL.from_components(components=(0.9, 0, 0, 0.2 * np.exp(1j))) 107 | 108 | EM = Vector_mask_XY(x0, y0, wavelength) 109 | EM.from_py_pol(PL) 110 | 111 | EM.draw(kind='amplitudes') 112 | save_figure_test(newpath, func_name, add_name='_amplitude') 113 | EM.draw(kind='phase') 114 | save_figure_test(newpath, func_name, add_name='_phase') 115 | assert True 116 | 117 | def test_polarizer_linear(self): 118 | func_name = sys._getframe().f_code.co_name 119 | # filename = '{}{}.npz'.format(newpath, func_name) 120 | 121 | length = 250*um 122 | num_data = 256 123 | wavelength = 0.6328*um 124 | 125 | x0 = np.linspace(-length/2, length/2, num_data) 126 | y0 = np.linspace(-length/2, length/2, num_data) 127 | 128 | EM = Vector_mask_XY(x0, y0, wavelength) 129 | EM.polarizer_linear(azimuth=0*degrees) 130 | 131 | EM.draw(kind='amplitudes') 132 | save_figure_test(newpath, func_name, add_name='_amplitude') 133 | EM.draw(kind='phase') 134 | save_figure_test(newpath, func_name, add_name='_phase') 135 | assert True 136 | 137 | def test_quarter_wave(self): 138 | func_name = sys._getframe().f_code.co_name 139 | # filename = '{}{}.npz'.format(newpath, func_name) 140 | 141 | length = 250*um 142 | num_data = 256 143 | wavelength = 0.6328*um 144 | 145 | x0 = np.linspace(-length/2, length/2, num_data) 146 | y0 = np.linspace(-length/2, length/2, num_data) 147 | 148 | EM = Vector_mask_XY(x0, y0, wavelength) 149 | EM.quarter_waveplate(azimuth=0*degrees) 150 | 151 | EM.draw(kind='amplitudes') 152 | save_figure_test(newpath, func_name, add_name='_amplitude') 153 | EM.draw(kind='phase') 154 | save_figure_test(newpath, func_name, add_name='_phase') 155 | assert True 156 | 157 | def test_half_wave(self): 158 | func_name = sys._getframe().f_code.co_name 159 | # filename = '{}{}.npz'.format(newpath, func_name) 160 | 161 | length = 250*um 162 | num_data = 256 163 | wavelength = 0.6328*um 164 | 165 | x0 = np.linspace(-length/2, length/2, num_data) 166 | y0 = np.linspace(-length/2, length/2, num_data) 167 | 168 | EM = Vector_mask_XY(x0, y0, wavelength) 169 | EM.half_waveplate(azimuth=0*degrees) 170 | 171 | EM.draw(kind='amplitudes') 172 | save_figure_test(newpath, func_name, add_name='_amplitude') 173 | EM.draw(kind='phase') 174 | save_figure_test(newpath, func_name, add_name='_phase') 175 | assert True 176 | 177 | def test_polarizer_retarder(self): 178 | func_name = sys._getframe().f_code.co_name 179 | # filename = '{}{}.npz'.format(newpath, func_name) 180 | 181 | length = 250*um 182 | num_data = 256 183 | wavelength = 0.6328*um 184 | 185 | x0 = np.linspace(-length/2, length/2, num_data) 186 | y0 = np.linspace(-length/2, length/2, num_data) 187 | 188 | EM = Vector_mask_XY(x0, y0, wavelength) 189 | EM.polarizer_retarder(R=90*degrees, 190 | p1=0.9, 191 | p2=0.1, 192 | azimuth=0*degrees) 193 | 194 | EM.draw(kind='amplitudes') 195 | save_figure_test(newpath, func_name, add_name='_amplitude') 196 | EM.draw(kind='phase') 197 | save_figure_test(newpath, func_name, add_name='_phase') 198 | assert True 199 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py38, flake8 3 | 4 | [travis] 5 | python = 6 | 3.8: py38 7 | 3.9: py39 8 | 3.10: py310 9 | 3.11: py322 10 | 11 | [testenv:flake8] 12 | basepython = python 13 | deps = flake8 14 | commands = flake8 diffractio 15 | 16 | [testenv] 17 | setenv = 18 | PYTHONPATH = {toxinidir} 19 | deps = 20 | -r{toxinidir}/requirements_dev.txt 21 | ; If you want to make tox run the tests with the same versions, create a 22 | ; requirements.txt with the pinned versions and uncomment the following line: 23 | ; -r{toxinidir}/requirements.txt 24 | commands = 25 | pip3 install -U pip 26 | py.test --basetemp={envtmpdir} 27 | -------------------------------------------------------------------------------- /usage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage1.png -------------------------------------------------------------------------------- /usage10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage10.png -------------------------------------------------------------------------------- /usage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage2.png -------------------------------------------------------------------------------- /usage3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage3.png -------------------------------------------------------------------------------- /usage4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage4.png -------------------------------------------------------------------------------- /usage5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage5.png -------------------------------------------------------------------------------- /usage6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage6.png -------------------------------------------------------------------------------- /usage7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage7.png -------------------------------------------------------------------------------- /usage8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage8.png -------------------------------------------------------------------------------- /usage9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aocg-ucm/diffractio/7110305ffa508eb2ed268e1e07a291029a240b64/usage9.png --------------------------------------------------------------------------------